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 * 26b51a60ccSBrian Somers * $Id: datalink.c,v 1.24 1999/01/12 21:50:20 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: 30647dd77c1SBrian Somers dl->phone.alt = NULL; 307c5a5a6caSBrian Somers datalink_LoginDone(dl); 308b51a60ccSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3093006ec67SBrian Somers } 3103006ec67SBrian Somers break; 3113006ec67SBrian Somers case CHAT_FAILED: 3123006ec67SBrian Somers /* Going down - script failed */ 313dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 31439d94652SBrian Somers chat_Destroy(&dl->chat); 3153006ec67SBrian Somers switch(dl->state) { 3163006ec67SBrian Somers case DATALINK_HANGUP: 3173006ec67SBrian Somers datalink_HangupDone(dl); 3183006ec67SBrian Somers break; 3193006ec67SBrian Somers case DATALINK_DIAL: 3203006ec67SBrian Somers case DATALINK_LOGIN: 3219ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 322d4af231cSBrian Somers modem_Offline(dl->physical); /* Is this required ? */ 323f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 3241342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3253006ec67SBrian Somers } 3263006ec67SBrian Somers break; 3273006ec67SBrian Somers } 3283006ec67SBrian Somers break; 329c7cc5030SBrian Somers 330c7cc5030SBrian Somers case DATALINK_READY: 331e2ebb036SBrian Somers case DATALINK_LCP: 332e2ebb036SBrian Somers case DATALINK_AUTH: 33392b09558SBrian Somers case DATALINK_CBCP: 3343006ec67SBrian Somers case DATALINK_OPEN: 3353006ec67SBrian Somers result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3363006ec67SBrian Somers break; 3373006ec67SBrian Somers } 3383006ec67SBrian Somers return result; 3393006ec67SBrian Somers } 3403006ec67SBrian Somers 341ea722969SBrian Somers int 342ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 343ea722969SBrian Somers { 344ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 345ea722969SBrian Somers } 346ea722969SBrian Somers 3473006ec67SBrian Somers static int 3482f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3493006ec67SBrian Somers { 3503006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3513006ec67SBrian Somers 3523006ec67SBrian Somers switch (dl->state) { 3533006ec67SBrian Somers case DATALINK_CLOSED: 354c7cc5030SBrian Somers case DATALINK_OPENING: 3553006ec67SBrian Somers break; 356c7cc5030SBrian Somers 3573006ec67SBrian Somers case DATALINK_HANGUP: 3583006ec67SBrian Somers case DATALINK_DIAL: 3593006ec67SBrian Somers case DATALINK_LOGIN: 3603006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 361c7cc5030SBrian Somers 362c7cc5030SBrian Somers case DATALINK_READY: 363e2ebb036SBrian Somers case DATALINK_LCP: 364e2ebb036SBrian Somers case DATALINK_AUTH: 36592b09558SBrian Somers case DATALINK_CBCP: 3663006ec67SBrian Somers case DATALINK_OPEN: 3673006ec67SBrian Somers return descriptor_IsSet(&dl->physical->desc, fdset); 3683006ec67SBrian Somers } 3693006ec67SBrian Somers return 0; 3703006ec67SBrian Somers } 3713006ec67SBrian Somers 3723006ec67SBrian Somers static void 3733006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3743006ec67SBrian Somers { 3753006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3763006ec67SBrian Somers 3773006ec67SBrian Somers switch (dl->state) { 3783006ec67SBrian Somers case DATALINK_CLOSED: 379c7cc5030SBrian Somers case DATALINK_OPENING: 3803006ec67SBrian Somers break; 381c7cc5030SBrian Somers 3823006ec67SBrian Somers case DATALINK_HANGUP: 3833006ec67SBrian Somers case DATALINK_DIAL: 3843006ec67SBrian Somers case DATALINK_LOGIN: 3853006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 3863006ec67SBrian Somers break; 387c7cc5030SBrian Somers 388c7cc5030SBrian Somers case DATALINK_READY: 389e2ebb036SBrian Somers case DATALINK_LCP: 390e2ebb036SBrian Somers case DATALINK_AUTH: 39192b09558SBrian Somers case DATALINK_CBCP: 3923006ec67SBrian Somers case DATALINK_OPEN: 3933006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 3943006ec67SBrian Somers break; 3953006ec67SBrian Somers } 3963006ec67SBrian Somers } 3973006ec67SBrian Somers 3981af29a6eSBrian Somers static int 399f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 4003006ec67SBrian Somers { 4013006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4021af29a6eSBrian Somers int result = 0; 4033006ec67SBrian Somers 4043006ec67SBrian Somers switch (dl->state) { 4053006ec67SBrian Somers case DATALINK_CLOSED: 406c7cc5030SBrian Somers case DATALINK_OPENING: 4073006ec67SBrian Somers break; 408c7cc5030SBrian Somers 4093006ec67SBrian Somers case DATALINK_HANGUP: 4103006ec67SBrian Somers case DATALINK_DIAL: 4113006ec67SBrian Somers case DATALINK_LOGIN: 4121af29a6eSBrian Somers result = descriptor_Write(&dl->chat.desc, bundle, fdset); 4133006ec67SBrian Somers break; 414c7cc5030SBrian Somers 415c7cc5030SBrian Somers case DATALINK_READY: 416e2ebb036SBrian Somers case DATALINK_LCP: 417e2ebb036SBrian Somers case DATALINK_AUTH: 41892b09558SBrian Somers case DATALINK_CBCP: 4193006ec67SBrian Somers case DATALINK_OPEN: 4201af29a6eSBrian Somers result = descriptor_Write(&dl->physical->desc, bundle, fdset); 4213006ec67SBrian Somers break; 4223006ec67SBrian Somers } 4231af29a6eSBrian Somers 4241af29a6eSBrian Somers return result; 4253006ec67SBrian Somers } 4263006ec67SBrian Somers 4276d666775SBrian Somers static void 4289c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 429e2ebb036SBrian Somers { 4309c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 431e2ebb036SBrian Somers dl->dial_tries = -1; 432e2ebb036SBrian Somers dl->reconnect_tries = 0; 4337729a182SBrian Somers if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 4349c81b87dSBrian Somers dl->stayonline = 1; 435e2ebb036SBrian Somers } 436e2ebb036SBrian Somers 4377729a182SBrian Somers if (dl->state >= DATALINK_READY && dl->stayonline) { 4389c81b87dSBrian Somers dl->stayonline = 0; 439d4af231cSBrian Somers timer_Stop(&dl->physical->Timer); 4409c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY); 4419c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 442e2ebb036SBrian Somers modem_Offline(dl->physical); 443b6f5f442SBrian Somers chat_Destroy(&dl->chat); 444e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4459ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 446f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 447e2ebb036SBrian Somers } else 448e2ebb036SBrian Somers datalink_HangupDone(dl); 449e2ebb036SBrian Somers } 450e2ebb036SBrian Somers } 451e2ebb036SBrian Somers 452e2ebb036SBrian Somers static void 4536d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4546d666775SBrian Somers { 4556d666775SBrian Somers /* The given FSM is about to start up ! */ 4566d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 457a611cad6SBrian Somers 45892e872e7SBrian Somers if (fp->proto == PROTO_LCP) 459e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 460e2ebb036SBrian Somers } 4616d666775SBrian Somers 4626d666775SBrian Somers static void 4636d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4646d666775SBrian Somers { 4656d666775SBrian Somers /* The given fsm is now up */ 4666d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4676d666775SBrian Somers 46892e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 469643f4904SBrian Somers datalink_GotAuthname(dl, "", 0); 4703b0f8d2eSBrian Somers dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 4713b0f8d2eSBrian Somers dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 4723b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 4733b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 4745563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 475dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 4763b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.his_auth), 4773b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.want_auth)); 4783b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth == PROTO_PAP) 479dd7e2610SBrian Somers auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 4803b0f8d2eSBrian Somers if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 481dd7e2610SBrian Somers auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 482e2ebb036SBrian Somers } else 483e2ebb036SBrian Somers datalink_AuthOk(dl); 484e2ebb036SBrian Somers } 485e2ebb036SBrian Somers } 486e2ebb036SBrian Somers 487e2ebb036SBrian Somers void 488643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len) 489643f4904SBrian Somers { 490643f4904SBrian Somers if (len >= sizeof dl->peer.authname) 491643f4904SBrian Somers len = sizeof dl->peer.authname - 1; 492643f4904SBrian Somers strncpy(dl->peer.authname, name, len); 493643f4904SBrian Somers dl->peer.authname[len] = '\0'; 494643f4904SBrian Somers } 495643f4904SBrian Somers 496643f4904SBrian Somers void 49792b09558SBrian Somers datalink_NCPUp(struct datalink *dl) 498e2ebb036SBrian Somers { 49906337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 5001df0a3b9SBrian Somers 501dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 5021fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 5031fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 5041fa665f5SBrian Somers case MP_LINKSENT: 505ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 5061fa665f5SBrian Somers return; 5071fa665f5SBrian Somers case MP_UP: 5080a1b5c9dSBrian Somers /* First link in the bundle */ 50992b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 5100a1b5c9dSBrian Somers /* fall through */ 5111fa665f5SBrian Somers case MP_ADDED: 5120a1b5c9dSBrian Somers /* We're in multilink mode ! */ 5131df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 5141fa665f5SBrian Somers break; 5151fa665f5SBrian Somers case MP_FAILED: 51649052c95SBrian Somers datalink_AuthNotOk(dl); 51749052c95SBrian Somers return; 51849052c95SBrian Somers } 51949052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 520dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 521897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 522897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 52349052c95SBrian Somers return; 52450abd4c8SBrian Somers } else { 52550abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 526ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 52792b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 52850abd4c8SBrian Somers } 52949052c95SBrian Somers 53006337856SBrian Somers if (ccpok) { 531dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 532dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 53306337856SBrian Somers } 5349ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 5353b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 5363b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 5376d666775SBrian Somers } 538e2ebb036SBrian Somers 539e2ebb036SBrian Somers void 54092b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl) 54192b09558SBrian Somers { 54292b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 54392b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 54492b09558SBrian Somers } 54592b09558SBrian Somers 54692b09558SBrian Somers void 54792b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl) 54892b09558SBrian Somers { 54992b09558SBrian Somers cbcp_Down(&dl->cbcp); 55092b09558SBrian Somers datalink_CBCPComplete(dl); 55192b09558SBrian Somers } 55292b09558SBrian Somers 55392b09558SBrian Somers void 55492b09558SBrian Somers datalink_AuthOk(struct datalink *dl) 55592b09558SBrian Somers { 5565165af6fSBrian Somers if ((dl->physical->link.lcp.his_callback.opmask & 55792b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) || 5585165af6fSBrian Somers dl->physical->link.lcp.want_callback.opmask & 5595165af6fSBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) && 5605165af6fSBrian Somers !(dl->physical->link.lcp.want_callback.opmask & 5615165af6fSBrian Somers CALLBACK_BIT(CALLBACK_AUTH))) { 5625165af6fSBrian Somers /* We must have agreed CBCP if AUTH isn't there any more */ 56392b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP); 56492b09558SBrian Somers cbcp_Up(&dl->cbcp); 56592b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) { 5665165af6fSBrian Somers /* It's not CBCP */ 56792b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 56892b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 56992b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 57092b09558SBrian Somers } else 57192b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) { 57292b09558SBrian Somers case 0: 57392b09558SBrian Somers datalink_NCPUp(dl); 57492b09558SBrian Somers break; 57592b09558SBrian Somers 57692b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH): 57792b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 57892b09558SBrian Somers sizeof dl->cbcp.fsm.phone); 57992b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 58092b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 58192b09558SBrian Somers dl->peer.authname); 58292b09558SBrian Somers *dl->cbcp.fsm.phone = '\0'; 58392b09558SBrian Somers } else { 58492b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ','); 58592b09558SBrian Somers if (ptr) 58692b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */ 58792b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 58892b09558SBrian Somers dl->cbcp.fsm.phone); 58992b09558SBrian Somers dl->cbcp.required = 1; 59092b09558SBrian Somers } 59192b09558SBrian Somers dl->cbcp.fsm.delay = 0; 59292b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 59392b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 59492b09558SBrian Somers break; 59592b09558SBrian Somers 59692b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164): 59792b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 59892b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1); 59992b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 60092b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 60192b09558SBrian Somers dl->cbcp.fsm.phone); 60292b09558SBrian Somers dl->cbcp.required = 1; 60392b09558SBrian Somers dl->cbcp.fsm.delay = 0; 60492b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 60592b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60692b09558SBrian Somers break; 60792b09558SBrian Somers 60892b09558SBrian Somers default: 60992b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 61092b09558SBrian Somers dl->name); 61192b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 61292b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 61392b09558SBrian Somers break; 61492b09558SBrian Somers } 61592b09558SBrian Somers } 61692b09558SBrian Somers 61792b09558SBrian Somers void 618e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 619e2ebb036SBrian Somers { 6209ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 621dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 6226d666775SBrian Somers } 6236d666775SBrian Somers 6246d666775SBrian Somers static void 6256d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 6266d666775SBrian Somers { 6276d666775SBrian Somers /* The given FSM has been told to come down */ 6286d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 629a611cad6SBrian Somers 63092e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 631e2ebb036SBrian Somers switch (dl->state) { 632e2ebb036SBrian Somers case DATALINK_OPEN: 633643f4904SBrian Somers peerid_Init(&dl->peer); 63409206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 635ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 636e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 63792b09558SBrian Somers /* fall through (just in case) */ 63892b09558SBrian Somers 63992b09558SBrian Somers case DATALINK_CBCP: 64092b09558SBrian Somers if (!dl->cbcp.required) 64192b09558SBrian Somers cbcp_Down(&dl->cbcp); 64292b09558SBrian Somers /* fall through (just in case) */ 643e2ebb036SBrian Somers 644e2ebb036SBrian Somers case DATALINK_AUTH: 645dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 646dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 6476d666775SBrian Somers } 6489ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 649e2ebb036SBrian Somers } 6506d666775SBrian Somers } 6516d666775SBrian Somers 6526d666775SBrian Somers static void 6536d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 6546d666775SBrian Somers { 6556d666775SBrian Somers /* The given fsm is now down */ 6566d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 6576d666775SBrian Somers 65892e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 65909206a6fSBrian Somers fsm2initial(fp); 6606d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 6619c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 6620a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 6630a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 6646d666775SBrian Somers } 6656d666775SBrian Somers 6663006ec67SBrian Somers struct datalink * 6676f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 6683006ec67SBrian Somers { 6693006ec67SBrian Somers struct datalink *dl; 6703006ec67SBrian Somers 6713006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 6723006ec67SBrian Somers if (dl == NULL) 6733006ec67SBrian Somers return dl; 6743006ec67SBrian Somers 6753006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 6763006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 6773006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 6783006ec67SBrian Somers dl->desc.Read = datalink_Read; 6793006ec67SBrian Somers dl->desc.Write = datalink_Write; 6805b8b8060SBrian Somers 681e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 682e718d1d7SBrian Somers 68373a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 68473a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 68573a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 686f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 687f9545805SBrian Somers *dl->phone.list = '\0'; 688f9545805SBrian Somers dl->phone.next = NULL; 689f9545805SBrian Somers dl->phone.alt = NULL; 690f9545805SBrian Somers dl->phone.chosen = "N/A"; 6919c81b87dSBrian Somers dl->stayonline = 0; 692c7cc5030SBrian Somers dl->script.run = 1; 693c7cc5030SBrian Somers dl->script.packetmode = 1; 6943b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 6955b8b8060SBrian Somers 6963006ec67SBrian Somers dl->bundle = bundle; 6973006ec67SBrian Somers dl->next = NULL; 698e718d1d7SBrian Somers 6993006ec67SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 700e718d1d7SBrian Somers 7013006ec67SBrian Somers dl->dial_tries = 0; 702565e35e5SBrian Somers dl->cfg.dial.max = 1; 703565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 704565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 705e718d1d7SBrian Somers 706abff9baeSBrian Somers dl->reconnect_tries = 0; 707565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 708565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 709abff9baeSBrian Somers 71092b09558SBrian Somers dl->cfg.callback.opmask = 0; 71192b09558SBrian Somers dl->cfg.cbcp.delay = 0; 71292b09558SBrian Somers *dl->cfg.cbcp.phone = '\0'; 71392b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 71492b09558SBrian Somers 7153006ec67SBrian Somers dl->name = strdup(name); 716643f4904SBrian Somers peerid_Init(&dl->peer); 7176f384573SBrian Somers dl->parent = &bundle->fsm; 7183b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 7193b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 7203b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 7213b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 7223b0f8d2eSBrian Somers dl->fsmp.object = dl; 7233b0f8d2eSBrian Somers 724dd7e2610SBrian Somers auth_Init(&dl->pap); 725dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 7263b0f8d2eSBrian Somers 727565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 7283006ec67SBrian Somers free(dl->name); 7293006ec67SBrian Somers free(dl); 7303006ec67SBrian Somers return NULL; 7313006ec67SBrian Somers } 73292b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 733f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 7343006ec67SBrian Somers 7359ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 7369ae58882SBrian Somers dl->name, datalink_State(dl)); 7373006ec67SBrian Somers 7383006ec67SBrian Somers return dl; 7393006ec67SBrian Somers } 7403006ec67SBrian Somers 7413006ec67SBrian Somers struct datalink * 742cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 743cd7bd93aSBrian Somers { 744cd7bd93aSBrian Somers struct datalink *dl; 745cd7bd93aSBrian Somers 746cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 747cd7bd93aSBrian Somers if (dl == NULL) 748cd7bd93aSBrian Somers return dl; 749cd7bd93aSBrian Somers 750cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 751cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 752cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 753cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 754cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 755cd7bd93aSBrian Somers 756cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 757cd7bd93aSBrian Somers 758cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 759cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 760cd7bd93aSBrian Somers *dl->phone.list = '\0'; 761643f4904SBrian Somers dl->phone.next = NULL; 762643f4904SBrian Somers dl->phone.alt = NULL; 763643f4904SBrian Somers dl->phone.chosen = "N/A"; 764cd7bd93aSBrian Somers dl->bundle = odl->bundle; 765cd7bd93aSBrian Somers dl->next = NULL; 766cd7bd93aSBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 767cd7bd93aSBrian Somers dl->dial_tries = 0; 768cd7bd93aSBrian Somers dl->reconnect_tries = 0; 769cd7bd93aSBrian Somers dl->name = strdup(name); 770643f4904SBrian Somers peerid_Init(&dl->peer); 771cd7bd93aSBrian Somers dl->parent = odl->parent; 772cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 773643f4904SBrian Somers dl->fsmp.object = dl; 774dd7e2610SBrian Somers auth_Init(&dl->pap); 775cd7bd93aSBrian Somers dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 776cd7bd93aSBrian Somers 777dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 778cd7bd93aSBrian Somers dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 779cd7bd93aSBrian Somers 78081358fa3SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 781cd7bd93aSBrian Somers free(dl->name); 782cd7bd93aSBrian Somers free(dl); 783cd7bd93aSBrian Somers return NULL; 784cd7bd93aSBrian Somers } 785cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 786cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 787cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 788cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 789cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 790cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 791cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 792cd7bd93aSBrian Somers 79392b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 794cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 795cd7bd93aSBrian Somers 7969ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 7979ae58882SBrian Somers dl->name, datalink_State(dl)); 798cd7bd93aSBrian Somers 799cd7bd93aSBrian Somers return dl; 800cd7bd93aSBrian Somers } 801cd7bd93aSBrian Somers 802cd7bd93aSBrian Somers struct datalink * 8033006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 8043006ec67SBrian Somers { 8053006ec67SBrian Somers struct datalink *result; 8063006ec67SBrian Somers 80739d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 808dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 809c7cc5030SBrian Somers datalink_State(dl)); 81039d94652SBrian Somers switch (dl->state) { 81139d94652SBrian Somers case DATALINK_HANGUP: 81239d94652SBrian Somers case DATALINK_DIAL: 81339d94652SBrian Somers case DATALINK_LOGIN: 81439d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 81539d94652SBrian Somers break; 81639d94652SBrian Somers } 81739d94652SBrian Somers } 8183006ec67SBrian Somers 819f1e8dfb2SBrian Somers timer_Stop(&dl->dial_timer); 8203006ec67SBrian Somers result = dl->next; 8213b0f8d2eSBrian Somers modem_Destroy(dl->physical); 8223006ec67SBrian Somers free(dl->name); 8233006ec67SBrian Somers free(dl); 8243006ec67SBrian Somers 8253006ec67SBrian Somers return result; 8263006ec67SBrian Somers } 8273006ec67SBrian Somers 8283006ec67SBrian Somers void 829c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 8303006ec67SBrian Somers { 8316f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 832565e35e5SBrian Somers /* Ignore scripts */ 833565e35e5SBrian Somers runscripts = 0; 834565e35e5SBrian Somers 835c7cc5030SBrian Somers switch (dl->state) { 836c7cc5030SBrian Somers case DATALINK_CLOSED: 8373b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 8383b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 8393b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 8409ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 841565e35e5SBrian Somers dl->reconnect_tries = 8426f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 843565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 844c5a5a6caSBrian Somers dl->script.run = runscripts; 845c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 846c7cc5030SBrian Somers break; 847c7cc5030SBrian Somers 848c7cc5030SBrian Somers case DATALINK_OPENING: 849c7cc5030SBrian Somers if (!dl->script.run && runscripts) 850c7cc5030SBrian Somers dl->script.run = 1; 851c7cc5030SBrian Somers /* fall through */ 852c7cc5030SBrian Somers 853c7cc5030SBrian Somers case DATALINK_DIAL: 854c7cc5030SBrian Somers case DATALINK_LOGIN: 855c7cc5030SBrian Somers case DATALINK_READY: 856c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 857c7cc5030SBrian Somers dl->script.packetmode = 1; 858c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 859c7cc5030SBrian Somers datalink_LoginDone(dl); 860c7cc5030SBrian Somers } 861c7cc5030SBrian Somers break; 8623006ec67SBrian Somers } 8633006ec67SBrian Somers } 8643006ec67SBrian Somers 8653006ec67SBrian Somers void 8669c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 867c7cc5030SBrian Somers { 868c7cc5030SBrian Somers /* Please close */ 869e2ebb036SBrian Somers switch (dl->state) { 870e2ebb036SBrian Somers case DATALINK_OPEN: 871643f4904SBrian Somers peerid_Init(&dl->peer); 87209206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 873e2ebb036SBrian Somers /* fall through */ 874e2ebb036SBrian Somers 87592b09558SBrian Somers case DATALINK_CBCP: 876e2ebb036SBrian Somers case DATALINK_AUTH: 877e2ebb036SBrian Somers case DATALINK_LCP: 878dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 8799c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 880c7cc5030SBrian Somers dl->dial_tries = -1; 881c7cc5030SBrian Somers dl->reconnect_tries = 0; 8829c81b87dSBrian Somers if (how == CLOSE_LCP) 8839c81b87dSBrian Somers dl->stayonline = 1; 884c7cc5030SBrian Somers } 885e2ebb036SBrian Somers break; 886e2ebb036SBrian Somers 887e2ebb036SBrian Somers default: 8889c81b87dSBrian Somers datalink_ComeDown(dl, how); 889c7cc5030SBrian Somers } 890e2ebb036SBrian Somers } 891c7cc5030SBrian Somers 892c7cc5030SBrian Somers void 8939c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 894c7cc5030SBrian Somers { 895c7cc5030SBrian Somers /* Carrier is lost */ 896e2ebb036SBrian Somers switch (dl->state) { 897e2ebb036SBrian Somers case DATALINK_OPEN: 898643f4904SBrian Somers peerid_Init(&dl->peer); 89909206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 900e2ebb036SBrian Somers /* fall through */ 901e2ebb036SBrian Somers 90292b09558SBrian Somers case DATALINK_CBCP: 903e2ebb036SBrian Somers case DATALINK_AUTH: 904e2ebb036SBrian Somers case DATALINK_LCP: 90509206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 906e2ebb036SBrian Somers /* fall through */ 907c7cc5030SBrian Somers 908e2ebb036SBrian Somers default: 9099c81b87dSBrian Somers datalink_ComeDown(dl, how); 910c7cc5030SBrian Somers } 911e2ebb036SBrian Somers } 912c7cc5030SBrian Somers 913c7cc5030SBrian Somers void 9143006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 9153006ec67SBrian Somers { 9163006ec67SBrian Somers dl->reconnect_tries = 0; 9173006ec67SBrian Somers } 918c7cc5030SBrian Somers 9199c81b87dSBrian Somers void 9209c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 9219c81b87dSBrian Somers { 9227729a182SBrian Somers if (dl->state >= DATALINK_LCP) 9239c81b87dSBrian Somers dl->stayonline = 1; 9249c81b87dSBrian Somers } 9259c81b87dSBrian Somers 926643f4904SBrian Somers int 927643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 928c7cc5030SBrian Somers { 929643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 930643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 931643f4904SBrian Somers datalink_State(arg->cx)); 932643f4904SBrian Somers prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 933643f4904SBrian Somers arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 934643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 935643f4904SBrian Somers if (*arg->cx->peer.authname) 936643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 937643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 938643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 939565e35e5SBrian Somers else 940643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 941643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 942643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 943643f4904SBrian Somers arg->cx->peer.enddisc.address, 944643f4904SBrian Somers arg->cx->peer.enddisc.len)); 945643f4904SBrian Somers 946643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 947643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 948643f4904SBrian Somers arg->cx->cfg.phone.list); 949643f4904SBrian Somers if (arg->cx->cfg.dial.max) 950643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 951643f4904SBrian Somers arg->cx->cfg.dial.max); 952565e35e5SBrian Somers else 953643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 954643f4904SBrian Somers if (arg->cx->cfg.dial.next_timeout > 0) 955643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 956565e35e5SBrian Somers else 957643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 958643f4904SBrian Somers if (arg->cx->cfg.dial.timeout > 0) 959643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 960565e35e5SBrian Somers else 961643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 962643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 963643f4904SBrian Somers arg->cx->cfg.reconnect.max); 964643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 965643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 966643f4904SBrian Somers else 967643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 96892b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 96992b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 97092b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 97192b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 97292b09558SBrian Somers else { 97392b09558SBrian Somers int comma = 0; 97492b09558SBrian Somers 97592b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 97692b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 97792b09558SBrian Somers comma = 1; 97892b09558SBrian Somers } 97992b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 98092b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 98192b09558SBrian Somers comma = 1; 98292b09558SBrian Somers } 98392b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 98492b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 98592b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 98692b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 98792b09558SBrian Somers comma = 1; 98892b09558SBrian Somers } 98992b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 99092b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 99192b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 99292b09558SBrian Somers arg->cx->cfg.cbcp.delay); 993cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: "); 994cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 995cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT) 996cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n"); 997cf784a89SBrian Somers else 998cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n"); 999cf784a89SBrian Somers } else 1000cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 100192b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 100292b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 100392b09558SBrian Somers } else 100492b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 100592b09558SBrian Somers } 100692b09558SBrian Somers 1007643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 1008643f4904SBrian Somers arg->cx->cfg.script.dial); 1009643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 1010643f4904SBrian Somers arg->cx->cfg.script.login); 1011643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1012643f4904SBrian Somers arg->cx->cfg.script.hangup); 1013643f4904SBrian Somers return 0; 1014565e35e5SBrian Somers } 1015565e35e5SBrian Somers 1016565e35e5SBrian Somers int 1017565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1018565e35e5SBrian Somers { 101925092092SBrian Somers if (arg->argc == arg->argn+2) { 102025092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 102125092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1022565e35e5SBrian Somers return 0; 1023565e35e5SBrian Somers } 1024565e35e5SBrian Somers return -1; 1025565e35e5SBrian Somers } 1026565e35e5SBrian Somers 1027565e35e5SBrian Somers int 1028565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1029565e35e5SBrian Somers { 1030565e35e5SBrian Somers int timeout; 1031565e35e5SBrian Somers int tries; 1032565e35e5SBrian Somers char *dot; 1033565e35e5SBrian Somers 103425092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 103525092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 103625092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1037565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1038565e35e5SBrian Somers randinit(); 1039565e35e5SBrian Somers } else { 104025092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1041565e35e5SBrian Somers 1042565e35e5SBrian Somers if (timeout >= 0) 1043565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1044565e35e5SBrian Somers else { 1045dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1046565e35e5SBrian Somers return -1; 1047565e35e5SBrian Somers } 1048565e35e5SBrian Somers } 1049565e35e5SBrian Somers 105025092092SBrian Somers dot = strchr(arg->argv[arg->argn], '.'); 1051565e35e5SBrian Somers if (dot) { 1052565e35e5SBrian Somers if (strcasecmp(++dot, "random") == 0) { 1053565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1054565e35e5SBrian Somers randinit(); 1055565e35e5SBrian Somers } else { 1056565e35e5SBrian Somers timeout = atoi(dot); 1057565e35e5SBrian Somers if (timeout >= 0) 1058565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1059565e35e5SBrian Somers else { 1060dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1061565e35e5SBrian Somers return -1; 1062565e35e5SBrian Somers } 1063565e35e5SBrian Somers } 1064565e35e5SBrian Somers } else 1065565e35e5SBrian Somers /* Default next timeout */ 1066565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1067565e35e5SBrian Somers 106825092092SBrian Somers if (arg->argc == arg->argn+2) { 106925092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1070565e35e5SBrian Somers 1071565e35e5SBrian Somers if (tries >= 0) { 1072565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1073565e35e5SBrian Somers } else { 1074dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1075565e35e5SBrian Somers return 1; 1076565e35e5SBrian Somers } 1077565e35e5SBrian Somers } 1078565e35e5SBrian Somers return 0; 1079565e35e5SBrian Somers } 1080565e35e5SBrian Somers return -1; 1081c7cc5030SBrian Somers } 1082c7cc5030SBrian Somers 1083cdbbb6b5SBrian Somers static const char *states[] = { 1084565e35e5SBrian Somers "closed", 1085565e35e5SBrian Somers "opening", 1086565e35e5SBrian Somers "hangup", 1087565e35e5SBrian Somers "dial", 1088565e35e5SBrian Somers "login", 1089565e35e5SBrian Somers "ready", 1090565e35e5SBrian Somers "lcp", 1091565e35e5SBrian Somers "auth", 109292b09558SBrian Somers "cbcp", 1093565e35e5SBrian Somers "open" 1094c7cc5030SBrian Somers }; 1095c7cc5030SBrian Somers 1096643f4904SBrian Somers const char * 1097c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1098c7cc5030SBrian Somers { 1099c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1100c7cc5030SBrian Somers return "unknown"; 1101c7cc5030SBrian Somers return states[dl->state]; 1102c7cc5030SBrian Somers } 11036f384573SBrian Somers 11049ae58882SBrian Somers static void 11059ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 11069ae58882SBrian Somers { 11079ae58882SBrian Somers if (state != dl->state) { 11089ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 11099ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 11109ae58882SBrian Somers states[state]); 11119ae58882SBrian Somers dl->state = state; 11129ae58882SBrian Somers } else 11139ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 11149ae58882SBrian Somers } 11159ae58882SBrian Somers } 11169ae58882SBrian Somers 11176f384573SBrian Somers struct datalink * 111896c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 111996c9bb21SBrian Somers int fd) 11206f384573SBrian Somers { 1121b7c5748eSBrian Somers struct datalink *dl, *cdl; 11226f384573SBrian Somers u_int retry; 1123b7c5748eSBrian Somers char *oname; 11246f384573SBrian Somers 112596c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 112696c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 11276f384573SBrian Somers 112896c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 112996c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 113096c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 113196c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 11326f384573SBrian Somers } 1133b7c5748eSBrian Somers 1134b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1135b7c5748eSBrian Somers oname = NULL; 1136b7c5748eSBrian Somers do { 1137b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1138b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1139b7c5748eSBrian Somers if (oname) 1140b7c5748eSBrian Somers free(datalink_NextName(dl)); 1141b7c5748eSBrian Somers else 1142b7c5748eSBrian Somers oname = datalink_NextName(dl); 1143b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1144b7c5748eSBrian Somers } 1145b7c5748eSBrian Somers } while (cdl); 1146b7c5748eSBrian Somers 1147b7c5748eSBrian Somers if (oname) { 1148b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1149b7c5748eSBrian Somers free(oname); 1150b7c5748eSBrian Somers } else { 115196c9bb21SBrian Somers dl->name = strdup(dl->name); 1152b7c5748eSBrian Somers free(iov[*niov].iov_base); 1153b7c5748eSBrian Somers } 1154b7c5748eSBrian Somers (*niov)++; 11556f384573SBrian Somers 11566f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 11576f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 11586f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 11596f384573SBrian Somers dl->desc.Read = datalink_Read; 11606f384573SBrian Somers dl->desc.Write = datalink_Write; 11616f384573SBrian Somers 11626f384573SBrian Somers mp_linkInit(&dl->mp); 11636f384573SBrian Somers *dl->phone.list = '\0'; 11646f384573SBrian Somers dl->phone.next = NULL; 11656f384573SBrian Somers dl->phone.alt = NULL; 11666f384573SBrian Somers dl->phone.chosen = "N/A"; 11676f384573SBrian Somers 11686f384573SBrian Somers dl->bundle = bundle; 11696f384573SBrian Somers dl->next = NULL; 11706f384573SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 11716f384573SBrian Somers dl->dial_tries = 0; 11726f384573SBrian Somers dl->reconnect_tries = 0; 11736f384573SBrian Somers dl->parent = &bundle->fsm; 11746f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 11756f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 11766f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 11776f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 11786f384573SBrian Somers dl->fsmp.object = dl; 11796f384573SBrian Somers 11806f384573SBrian Somers retry = dl->pap.cfg.fsmretry; 1181dd7e2610SBrian Somers auth_Init(&dl->pap); 11826f384573SBrian Somers dl->pap.cfg.fsmretry = retry; 11836f384573SBrian Somers 11846f384573SBrian Somers retry = dl->chap.auth.cfg.fsmretry; 1185dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 11866f384573SBrian Somers dl->chap.auth.cfg.fsmretry = retry; 11876f384573SBrian Somers 118896c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 118996c9bb21SBrian Somers 119096c9bb21SBrian Somers if (!dl->physical) { 11916f384573SBrian Somers free(dl->name); 11926f384573SBrian Somers free(dl); 11936f384573SBrian Somers dl = NULL; 11949ae58882SBrian Somers } else { 119592b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 11966f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 11976f384573SBrian Somers 11989ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 11999ae58882SBrian Somers dl->name, datalink_State(dl)); 12009ae58882SBrian Somers } 12019ae58882SBrian Somers 12026f384573SBrian Somers return dl; 12036f384573SBrian Somers } 12046f384573SBrian Somers 12056f384573SBrian Somers int 120685fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 120785fd273aSBrian Somers pid_t newpid) 12086f384573SBrian Somers { 120996c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 121096c9bb21SBrian Somers int link_fd; 12116f384573SBrian Somers 121296c9bb21SBrian Somers if (dl) { 1213dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 121492b09558SBrian Somers /* The following is purely for the sake of paranoia */ 121592b09558SBrian Somers cbcp_Down(&dl->cbcp); 1216dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1217dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 12186f384573SBrian Somers } 12196f384573SBrian Somers 122096c9bb21SBrian Somers if (*niov >= maxiov - 1) { 122196c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 122296c9bb21SBrian Somers if (dl) { 12236f384573SBrian Somers free(dl->name); 12246f384573SBrian Somers free(dl); 122596c9bb21SBrian Somers } 122696c9bb21SBrian Somers return -1; 122796c9bb21SBrian Somers } 122896c9bb21SBrian Somers 122996c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 123096c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 123196c9bb21SBrian Somers iov[*niov].iov_base = 123296c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 123396c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 123496c9bb21SBrian Somers 123585fd273aSBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 123696c9bb21SBrian Somers 123796c9bb21SBrian Somers if (link_fd == -1 && dl) { 123896c9bb21SBrian Somers free(dl->name); 123996c9bb21SBrian Somers free(dl); 124096c9bb21SBrian Somers } 12416f384573SBrian Somers 12426f384573SBrian Somers return link_fd; 12436f384573SBrian Somers } 12446f384573SBrian Somers 124558d55334SBrian Somers void 124658d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 124758d55334SBrian Somers { 124858d55334SBrian Somers free(dl->name); 124958d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 125058d55334SBrian Somers } 125158d55334SBrian Somers 125284917b87SBrian Somers char * 125384917b87SBrian Somers datalink_NextName(struct datalink *dl) 12546f384573SBrian Somers { 12556f384573SBrian Somers int f, n; 125684917b87SBrian Somers char *name, *oname; 12576f384573SBrian Somers 12586f384573SBrian Somers n = strlen(dl->name); 12596f384573SBrian Somers name = (char *)malloc(n+3); 12606f384573SBrian Somers for (f = n - 1; f >= 0; f--) 12616f384573SBrian Somers if (!isdigit(dl->name[f])) 12626f384573SBrian Somers break; 12636f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 12646f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 126584917b87SBrian Somers oname = dl->name; 126654cd8e13SBrian Somers dl->name = name; 126754cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 126884917b87SBrian Somers return oname; 12696f384573SBrian Somers } 1270dd0645c5SBrian Somers 1271dd0645c5SBrian Somers int 1272dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1273dd0645c5SBrian Somers { 1274dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1275dd0645c5SBrian Somers return 0; 1276dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1277dd0645c5SBrian Somers dl->script.run = 0; 1278dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1279dd0645c5SBrian Somers dl->reconnect_tries = 0; 128081358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1281dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1282dd0645c5SBrian Somers return 1; 1283dd0645c5SBrian Somers } 1284