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 * 26bf1d3ff6SBrian Somers * $Id: datalink.c,v 1.17 1998/08/07 18:42:48 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); 2591342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 260c5a5a6caSBrian Somers } else 261c5a5a6caSBrian Somers datalink_LoginDone(dl); 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); 442e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4439ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 444f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 445e2ebb036SBrian Somers } else 446e2ebb036SBrian Somers datalink_HangupDone(dl); 447e2ebb036SBrian Somers } 448e2ebb036SBrian Somers } 449e2ebb036SBrian Somers 450e2ebb036SBrian Somers static void 4516d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4526d666775SBrian Somers { 4536d666775SBrian Somers /* The given FSM is about to start up ! */ 4546d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 455a611cad6SBrian Somers 45692e872e7SBrian Somers if (fp->proto == PROTO_LCP) 457e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 458e2ebb036SBrian Somers } 4596d666775SBrian Somers 4606d666775SBrian Somers static void 4616d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4626d666775SBrian Somers { 4636d666775SBrian Somers /* The given fsm is now up */ 4646d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4656d666775SBrian Somers 46692e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 467643f4904SBrian Somers datalink_GotAuthname(dl, "", 0); 4683b0f8d2eSBrian Somers dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 4693b0f8d2eSBrian Somers dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 4703b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 4713b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 4725563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 473dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 4743b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.his_auth), 4753b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.want_auth)); 4763b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth == PROTO_PAP) 477dd7e2610SBrian Somers auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 4783b0f8d2eSBrian Somers if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 479dd7e2610SBrian Somers auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 480e2ebb036SBrian Somers } else 481e2ebb036SBrian Somers datalink_AuthOk(dl); 482e2ebb036SBrian Somers } 483e2ebb036SBrian Somers } 484e2ebb036SBrian Somers 485e2ebb036SBrian Somers void 486643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len) 487643f4904SBrian Somers { 488643f4904SBrian Somers if (len >= sizeof dl->peer.authname) 489643f4904SBrian Somers len = sizeof dl->peer.authname - 1; 490643f4904SBrian Somers strncpy(dl->peer.authname, name, len); 491643f4904SBrian Somers dl->peer.authname[len] = '\0'; 492643f4904SBrian Somers } 493643f4904SBrian Somers 494643f4904SBrian Somers void 49592b09558SBrian Somers datalink_NCPUp(struct datalink *dl) 496e2ebb036SBrian Somers { 49706337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 4981df0a3b9SBrian Somers 499dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 5001fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 5011fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 5021fa665f5SBrian Somers case MP_LINKSENT: 503ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 5041fa665f5SBrian Somers return; 5051fa665f5SBrian Somers case MP_UP: 5060a1b5c9dSBrian Somers /* First link in the bundle */ 50792b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 5080a1b5c9dSBrian Somers /* fall through */ 5091fa665f5SBrian Somers case MP_ADDED: 5100a1b5c9dSBrian Somers /* We're in multilink mode ! */ 5111df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 5121fa665f5SBrian Somers break; 5131fa665f5SBrian Somers case MP_FAILED: 51449052c95SBrian Somers datalink_AuthNotOk(dl); 51549052c95SBrian Somers return; 51649052c95SBrian Somers } 51749052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 518dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 519897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 520897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 52149052c95SBrian Somers return; 52250abd4c8SBrian Somers } else { 52350abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 524ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 52592b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 52650abd4c8SBrian Somers } 52749052c95SBrian Somers 52806337856SBrian Somers if (ccpok) { 529dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 530dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 53106337856SBrian Somers } 5329ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 5333b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 5343b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 5356d666775SBrian Somers } 536e2ebb036SBrian Somers 537e2ebb036SBrian Somers void 53892b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl) 53992b09558SBrian Somers { 54092b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 54192b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 54292b09558SBrian Somers } 54392b09558SBrian Somers 54492b09558SBrian Somers void 54592b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl) 54692b09558SBrian Somers { 54792b09558SBrian Somers cbcp_Down(&dl->cbcp); 54892b09558SBrian Somers datalink_CBCPComplete(dl); 54992b09558SBrian Somers } 55092b09558SBrian Somers 55192b09558SBrian Somers void 55292b09558SBrian Somers datalink_AuthOk(struct datalink *dl) 55392b09558SBrian Somers { 55492b09558SBrian Somers if (dl->physical->link.lcp.his_callback.opmask == 55592b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) || 55692b09558SBrian Somers dl->physical->link.lcp.want_callback.opmask == 55792b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) { 55892b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP); 55992b09558SBrian Somers cbcp_Up(&dl->cbcp); 56092b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) { 56192b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 56292b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 56392b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 56492b09558SBrian Somers } else 56592b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) { 56692b09558SBrian Somers case 0: 56792b09558SBrian Somers datalink_NCPUp(dl); 56892b09558SBrian Somers break; 56992b09558SBrian Somers 57092b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH): 57192b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 57292b09558SBrian Somers sizeof dl->cbcp.fsm.phone); 57392b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 57492b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 57592b09558SBrian Somers dl->peer.authname); 57692b09558SBrian Somers *dl->cbcp.fsm.phone = '\0'; 57792b09558SBrian Somers } else { 57892b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ','); 57992b09558SBrian Somers if (ptr) 58092b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */ 58192b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 58292b09558SBrian Somers dl->cbcp.fsm.phone); 58392b09558SBrian Somers dl->cbcp.required = 1; 58492b09558SBrian Somers } 58592b09558SBrian Somers dl->cbcp.fsm.delay = 0; 58692b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 58792b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 58892b09558SBrian Somers break; 58992b09558SBrian Somers 59092b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164): 59192b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 59292b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1); 59392b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 59492b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 59592b09558SBrian Somers dl->cbcp.fsm.phone); 59692b09558SBrian Somers dl->cbcp.required = 1; 59792b09558SBrian Somers dl->cbcp.fsm.delay = 0; 59892b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 59992b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60092b09558SBrian Somers break; 60192b09558SBrian Somers 60292b09558SBrian Somers default: 60392b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 60492b09558SBrian Somers dl->name); 60592b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 60692b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60792b09558SBrian Somers break; 60892b09558SBrian Somers } 60992b09558SBrian Somers } 61092b09558SBrian Somers 61192b09558SBrian Somers void 612e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 613e2ebb036SBrian Somers { 6149ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 615dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 6166d666775SBrian Somers } 6176d666775SBrian Somers 6186d666775SBrian Somers static void 6196d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 6206d666775SBrian Somers { 6216d666775SBrian Somers /* The given FSM has been told to come down */ 6226d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 623a611cad6SBrian Somers 62492e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 625e2ebb036SBrian Somers switch (dl->state) { 626e2ebb036SBrian Somers case DATALINK_OPEN: 627643f4904SBrian Somers peerid_Init(&dl->peer); 62809206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 629ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 630e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 63192b09558SBrian Somers /* fall through (just in case) */ 63292b09558SBrian Somers 63392b09558SBrian Somers case DATALINK_CBCP: 63492b09558SBrian Somers if (!dl->cbcp.required) 63592b09558SBrian Somers cbcp_Down(&dl->cbcp); 63692b09558SBrian Somers /* fall through (just in case) */ 637e2ebb036SBrian Somers 638e2ebb036SBrian Somers case DATALINK_AUTH: 639dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 640dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 6416d666775SBrian Somers } 6429ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 643e2ebb036SBrian Somers } 6446d666775SBrian Somers } 6456d666775SBrian Somers 6466d666775SBrian Somers static void 6476d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 6486d666775SBrian Somers { 6496d666775SBrian Somers /* The given fsm is now down */ 6506d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 6516d666775SBrian Somers 65292e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 65309206a6fSBrian Somers fsm2initial(fp); 6546d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 6559c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 6560a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 6570a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 6586d666775SBrian Somers } 6596d666775SBrian Somers 6603006ec67SBrian Somers struct datalink * 6616f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 6623006ec67SBrian Somers { 6633006ec67SBrian Somers struct datalink *dl; 6643006ec67SBrian Somers 6653006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 6663006ec67SBrian Somers if (dl == NULL) 6673006ec67SBrian Somers return dl; 6683006ec67SBrian Somers 6693006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 6703006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 6713006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 6723006ec67SBrian Somers dl->desc.Read = datalink_Read; 6733006ec67SBrian Somers dl->desc.Write = datalink_Write; 6745b8b8060SBrian Somers 675e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 676e718d1d7SBrian Somers 67773a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 67873a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 67973a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 680f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 681f9545805SBrian Somers *dl->phone.list = '\0'; 682f9545805SBrian Somers dl->phone.next = NULL; 683f9545805SBrian Somers dl->phone.alt = NULL; 684f9545805SBrian Somers dl->phone.chosen = "N/A"; 6859c81b87dSBrian Somers dl->stayonline = 0; 686c7cc5030SBrian Somers dl->script.run = 1; 687c7cc5030SBrian Somers dl->script.packetmode = 1; 6883b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 6895b8b8060SBrian Somers 6903006ec67SBrian Somers dl->bundle = bundle; 6913006ec67SBrian Somers dl->next = NULL; 692e718d1d7SBrian Somers 6933006ec67SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 694e718d1d7SBrian Somers 6953006ec67SBrian Somers dl->dial_tries = 0; 696565e35e5SBrian Somers dl->cfg.dial.max = 1; 697565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 698565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 699e718d1d7SBrian Somers 700abff9baeSBrian Somers dl->reconnect_tries = 0; 701565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 702565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 703abff9baeSBrian Somers 70492b09558SBrian Somers dl->cfg.callback.opmask = 0; 70592b09558SBrian Somers dl->cfg.cbcp.delay = 0; 70692b09558SBrian Somers *dl->cfg.cbcp.phone = '\0'; 70792b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 70892b09558SBrian Somers 7093006ec67SBrian Somers dl->name = strdup(name); 710643f4904SBrian Somers peerid_Init(&dl->peer); 7116f384573SBrian Somers dl->parent = &bundle->fsm; 7123b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 7133b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 7143b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 7153b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 7163b0f8d2eSBrian Somers dl->fsmp.object = dl; 7173b0f8d2eSBrian Somers 718dd7e2610SBrian Somers auth_Init(&dl->pap); 719dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 7203b0f8d2eSBrian Somers 721565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 7223006ec67SBrian Somers free(dl->name); 7233006ec67SBrian Somers free(dl); 7243006ec67SBrian Somers return NULL; 7253006ec67SBrian Somers } 72692b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 727f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 7283006ec67SBrian Somers 7299ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 7309ae58882SBrian Somers dl->name, datalink_State(dl)); 7313006ec67SBrian Somers 7323006ec67SBrian Somers return dl; 7333006ec67SBrian Somers } 7343006ec67SBrian Somers 7353006ec67SBrian Somers struct datalink * 736cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 737cd7bd93aSBrian Somers { 738cd7bd93aSBrian Somers struct datalink *dl; 739cd7bd93aSBrian Somers 740cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 741cd7bd93aSBrian Somers if (dl == NULL) 742cd7bd93aSBrian Somers return dl; 743cd7bd93aSBrian Somers 744cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 745cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 746cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 747cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 748cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 749cd7bd93aSBrian Somers 750cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 751cd7bd93aSBrian Somers 752cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 753cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 754cd7bd93aSBrian Somers *dl->phone.list = '\0'; 755643f4904SBrian Somers dl->phone.next = NULL; 756643f4904SBrian Somers dl->phone.alt = NULL; 757643f4904SBrian Somers dl->phone.chosen = "N/A"; 758cd7bd93aSBrian Somers dl->bundle = odl->bundle; 759cd7bd93aSBrian Somers dl->next = NULL; 760cd7bd93aSBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 761cd7bd93aSBrian Somers dl->dial_tries = 0; 762cd7bd93aSBrian Somers dl->reconnect_tries = 0; 763cd7bd93aSBrian Somers dl->name = strdup(name); 764643f4904SBrian Somers peerid_Init(&dl->peer); 765cd7bd93aSBrian Somers dl->parent = odl->parent; 766cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 767643f4904SBrian Somers dl->fsmp.object = dl; 768dd7e2610SBrian Somers auth_Init(&dl->pap); 769cd7bd93aSBrian Somers dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 770cd7bd93aSBrian Somers 771dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 772cd7bd93aSBrian Somers dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 773cd7bd93aSBrian Somers 77481358fa3SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 775cd7bd93aSBrian Somers free(dl->name); 776cd7bd93aSBrian Somers free(dl); 777cd7bd93aSBrian Somers return NULL; 778cd7bd93aSBrian Somers } 779cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 780cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 781cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 782cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 783cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 784cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 785cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 786cd7bd93aSBrian Somers 78792b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 788cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 789cd7bd93aSBrian Somers 7909ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 7919ae58882SBrian Somers dl->name, datalink_State(dl)); 792cd7bd93aSBrian Somers 793cd7bd93aSBrian Somers return dl; 794cd7bd93aSBrian Somers } 795cd7bd93aSBrian Somers 796cd7bd93aSBrian Somers struct datalink * 7973006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 7983006ec67SBrian Somers { 7993006ec67SBrian Somers struct datalink *result; 8003006ec67SBrian Somers 80139d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 802dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 803c7cc5030SBrian Somers datalink_State(dl)); 80439d94652SBrian Somers switch (dl->state) { 80539d94652SBrian Somers case DATALINK_HANGUP: 80639d94652SBrian Somers case DATALINK_DIAL: 80739d94652SBrian Somers case DATALINK_LOGIN: 80839d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 80939d94652SBrian Somers break; 81039d94652SBrian Somers } 81139d94652SBrian Somers } 8123006ec67SBrian Somers 8133006ec67SBrian Somers result = dl->next; 8143b0f8d2eSBrian Somers modem_Destroy(dl->physical); 8153006ec67SBrian Somers free(dl->name); 8163006ec67SBrian Somers free(dl); 8173006ec67SBrian Somers 8183006ec67SBrian Somers return result; 8193006ec67SBrian Somers } 8203006ec67SBrian Somers 8213006ec67SBrian Somers void 822c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 8233006ec67SBrian Somers { 8246f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 825565e35e5SBrian Somers /* Ignore scripts */ 826565e35e5SBrian Somers runscripts = 0; 827565e35e5SBrian Somers 828c7cc5030SBrian Somers switch (dl->state) { 829c7cc5030SBrian Somers case DATALINK_CLOSED: 8303b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 8313b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 8323b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 8339ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 834565e35e5SBrian Somers dl->reconnect_tries = 8356f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 836565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 837c5a5a6caSBrian Somers dl->script.run = runscripts; 838c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 839c7cc5030SBrian Somers break; 840c7cc5030SBrian Somers 841c7cc5030SBrian Somers case DATALINK_OPENING: 842c7cc5030SBrian Somers if (!dl->script.run && runscripts) 843c7cc5030SBrian Somers dl->script.run = 1; 844c7cc5030SBrian Somers /* fall through */ 845c7cc5030SBrian Somers 846c7cc5030SBrian Somers case DATALINK_DIAL: 847c7cc5030SBrian Somers case DATALINK_LOGIN: 848c7cc5030SBrian Somers case DATALINK_READY: 849c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 850c7cc5030SBrian Somers dl->script.packetmode = 1; 851c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 852c7cc5030SBrian Somers datalink_LoginDone(dl); 853c7cc5030SBrian Somers } 854c7cc5030SBrian Somers break; 8553006ec67SBrian Somers } 8563006ec67SBrian Somers } 8573006ec67SBrian Somers 8583006ec67SBrian Somers void 8599c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 860c7cc5030SBrian Somers { 861c7cc5030SBrian Somers /* Please close */ 862e2ebb036SBrian Somers switch (dl->state) { 863e2ebb036SBrian Somers case DATALINK_OPEN: 864643f4904SBrian Somers peerid_Init(&dl->peer); 86509206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 866e2ebb036SBrian Somers /* fall through */ 867e2ebb036SBrian Somers 86892b09558SBrian Somers case DATALINK_CBCP: 869e2ebb036SBrian Somers case DATALINK_AUTH: 870e2ebb036SBrian Somers case DATALINK_LCP: 871dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 8729c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 873c7cc5030SBrian Somers dl->dial_tries = -1; 874c7cc5030SBrian Somers dl->reconnect_tries = 0; 8759c81b87dSBrian Somers if (how == CLOSE_LCP) 8769c81b87dSBrian Somers dl->stayonline = 1; 877c7cc5030SBrian Somers } 878e2ebb036SBrian Somers break; 879e2ebb036SBrian Somers 880e2ebb036SBrian Somers default: 8819c81b87dSBrian Somers datalink_ComeDown(dl, how); 882c7cc5030SBrian Somers } 883e2ebb036SBrian Somers } 884c7cc5030SBrian Somers 885c7cc5030SBrian Somers void 8869c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 887c7cc5030SBrian Somers { 888c7cc5030SBrian Somers /* Carrier is lost */ 889e2ebb036SBrian Somers switch (dl->state) { 890e2ebb036SBrian Somers case DATALINK_OPEN: 891643f4904SBrian Somers peerid_Init(&dl->peer); 89209206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 893e2ebb036SBrian Somers /* fall through */ 894e2ebb036SBrian Somers 89592b09558SBrian Somers case DATALINK_CBCP: 896e2ebb036SBrian Somers case DATALINK_AUTH: 897e2ebb036SBrian Somers case DATALINK_LCP: 89809206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 899e2ebb036SBrian Somers /* fall through */ 900c7cc5030SBrian Somers 901e2ebb036SBrian Somers default: 9029c81b87dSBrian Somers datalink_ComeDown(dl, how); 903c7cc5030SBrian Somers } 904e2ebb036SBrian Somers } 905c7cc5030SBrian Somers 906c7cc5030SBrian Somers void 9073006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 9083006ec67SBrian Somers { 9093006ec67SBrian Somers dl->reconnect_tries = 0; 9103006ec67SBrian Somers } 911c7cc5030SBrian Somers 9129c81b87dSBrian Somers void 9139c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 9149c81b87dSBrian Somers { 9157729a182SBrian Somers if (dl->state >= DATALINK_LCP) 9169c81b87dSBrian Somers dl->stayonline = 1; 9179c81b87dSBrian Somers } 9189c81b87dSBrian Somers 919643f4904SBrian Somers int 920643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 921c7cc5030SBrian Somers { 922643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 923643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 924643f4904SBrian Somers datalink_State(arg->cx)); 925643f4904SBrian Somers prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 926643f4904SBrian Somers arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 927643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 928643f4904SBrian Somers if (*arg->cx->peer.authname) 929643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 930643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 931643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 932565e35e5SBrian Somers else 933643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 934643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 935643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 936643f4904SBrian Somers arg->cx->peer.enddisc.address, 937643f4904SBrian Somers arg->cx->peer.enddisc.len)); 938643f4904SBrian Somers 939643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 940643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 941643f4904SBrian Somers arg->cx->cfg.phone.list); 942643f4904SBrian Somers if (arg->cx->cfg.dial.max) 943643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 944643f4904SBrian Somers arg->cx->cfg.dial.max); 945565e35e5SBrian Somers else 946643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 947643f4904SBrian Somers if (arg->cx->cfg.dial.next_timeout > 0) 948643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 949565e35e5SBrian Somers else 950643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 951643f4904SBrian Somers if (arg->cx->cfg.dial.timeout > 0) 952643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 953565e35e5SBrian Somers else 954643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 955643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 956643f4904SBrian Somers arg->cx->cfg.reconnect.max); 957643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 958643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 959643f4904SBrian Somers else 960643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 96192b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 96292b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 96392b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 96492b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 96592b09558SBrian Somers else { 96692b09558SBrian Somers int comma = 0; 96792b09558SBrian Somers 96892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 96992b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 97092b09558SBrian Somers comma = 1; 97192b09558SBrian Somers } 97292b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 97392b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 97492b09558SBrian Somers comma = 1; 97592b09558SBrian Somers } 97692b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 97792b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 97892b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 97992b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 98092b09558SBrian Somers comma = 1; 98192b09558SBrian Somers } 98292b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 98392b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 98492b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 98592b09558SBrian Somers arg->cx->cfg.cbcp.delay); 98692b09558SBrian Somers prompt_Printf(arg->prompt, " phone: %s\n", 98792b09558SBrian Somers arg->cx->cfg.cbcp.phone); 98892b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 98992b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 99092b09558SBrian Somers } else 99192b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 99292b09558SBrian Somers } 99392b09558SBrian Somers 994643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 995643f4904SBrian Somers arg->cx->cfg.script.dial); 996643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 997643f4904SBrian Somers arg->cx->cfg.script.login); 998643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 999643f4904SBrian Somers arg->cx->cfg.script.hangup); 1000643f4904SBrian Somers return 0; 1001565e35e5SBrian Somers } 1002565e35e5SBrian Somers 1003565e35e5SBrian Somers int 1004565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1005565e35e5SBrian Somers { 100625092092SBrian Somers if (arg->argc == arg->argn+2) { 100725092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 100825092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1009565e35e5SBrian Somers return 0; 1010565e35e5SBrian Somers } 1011565e35e5SBrian Somers return -1; 1012565e35e5SBrian Somers } 1013565e35e5SBrian Somers 1014565e35e5SBrian Somers int 1015565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1016565e35e5SBrian Somers { 1017565e35e5SBrian Somers int timeout; 1018565e35e5SBrian Somers int tries; 1019565e35e5SBrian Somers char *dot; 1020565e35e5SBrian Somers 102125092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 102225092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 102325092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1024565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1025565e35e5SBrian Somers randinit(); 1026565e35e5SBrian Somers } else { 102725092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1028565e35e5SBrian Somers 1029565e35e5SBrian Somers if (timeout >= 0) 1030565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1031565e35e5SBrian Somers else { 1032dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1033565e35e5SBrian Somers return -1; 1034565e35e5SBrian Somers } 1035565e35e5SBrian Somers } 1036565e35e5SBrian Somers 103725092092SBrian Somers dot = strchr(arg->argv[arg->argn], '.'); 1038565e35e5SBrian Somers if (dot) { 1039565e35e5SBrian Somers if (strcasecmp(++dot, "random") == 0) { 1040565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1041565e35e5SBrian Somers randinit(); 1042565e35e5SBrian Somers } else { 1043565e35e5SBrian Somers timeout = atoi(dot); 1044565e35e5SBrian Somers if (timeout >= 0) 1045565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1046565e35e5SBrian Somers else { 1047dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1048565e35e5SBrian Somers return -1; 1049565e35e5SBrian Somers } 1050565e35e5SBrian Somers } 1051565e35e5SBrian Somers } else 1052565e35e5SBrian Somers /* Default next timeout */ 1053565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1054565e35e5SBrian Somers 105525092092SBrian Somers if (arg->argc == arg->argn+2) { 105625092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1057565e35e5SBrian Somers 1058565e35e5SBrian Somers if (tries >= 0) { 1059565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1060565e35e5SBrian Somers } else { 1061dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1062565e35e5SBrian Somers return 1; 1063565e35e5SBrian Somers } 1064565e35e5SBrian Somers } 1065565e35e5SBrian Somers return 0; 1066565e35e5SBrian Somers } 1067565e35e5SBrian Somers return -1; 1068c7cc5030SBrian Somers } 1069c7cc5030SBrian Somers 1070cdbbb6b5SBrian Somers static const char *states[] = { 1071565e35e5SBrian Somers "closed", 1072565e35e5SBrian Somers "opening", 1073565e35e5SBrian Somers "hangup", 1074565e35e5SBrian Somers "dial", 1075565e35e5SBrian Somers "login", 1076565e35e5SBrian Somers "ready", 1077565e35e5SBrian Somers "lcp", 1078565e35e5SBrian Somers "auth", 107992b09558SBrian Somers "cbcp", 1080565e35e5SBrian Somers "open" 1081c7cc5030SBrian Somers }; 1082c7cc5030SBrian Somers 1083643f4904SBrian Somers const char * 1084c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1085c7cc5030SBrian Somers { 1086c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1087c7cc5030SBrian Somers return "unknown"; 1088c7cc5030SBrian Somers return states[dl->state]; 1089c7cc5030SBrian Somers } 10906f384573SBrian Somers 10919ae58882SBrian Somers static void 10929ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 10939ae58882SBrian Somers { 10949ae58882SBrian Somers if (state != dl->state) { 10959ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 10969ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 10979ae58882SBrian Somers states[state]); 10989ae58882SBrian Somers dl->state = state; 10999ae58882SBrian Somers } else 11009ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 11019ae58882SBrian Somers } 11029ae58882SBrian Somers } 11039ae58882SBrian Somers 11046f384573SBrian Somers struct datalink * 110596c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 110696c9bb21SBrian Somers int fd) 11076f384573SBrian Somers { 1108b7c5748eSBrian Somers struct datalink *dl, *cdl; 11096f384573SBrian Somers u_int retry; 1110b7c5748eSBrian Somers char *oname; 11116f384573SBrian Somers 111296c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 111396c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 11146f384573SBrian Somers 111596c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 111696c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 111796c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 111896c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 11196f384573SBrian Somers } 1120b7c5748eSBrian Somers 1121b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1122b7c5748eSBrian Somers oname = NULL; 1123b7c5748eSBrian Somers do { 1124b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1125b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1126b7c5748eSBrian Somers if (oname) 1127b7c5748eSBrian Somers free(datalink_NextName(dl)); 1128b7c5748eSBrian Somers else 1129b7c5748eSBrian Somers oname = datalink_NextName(dl); 1130b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1131b7c5748eSBrian Somers } 1132b7c5748eSBrian Somers } while (cdl); 1133b7c5748eSBrian Somers 1134b7c5748eSBrian Somers if (oname) { 1135b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1136b7c5748eSBrian Somers free(oname); 1137b7c5748eSBrian Somers } else { 113896c9bb21SBrian Somers dl->name = strdup(dl->name); 1139b7c5748eSBrian Somers free(iov[*niov].iov_base); 1140b7c5748eSBrian Somers } 1141b7c5748eSBrian Somers (*niov)++; 11426f384573SBrian Somers 11436f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 11446f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 11456f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 11466f384573SBrian Somers dl->desc.Read = datalink_Read; 11476f384573SBrian Somers dl->desc.Write = datalink_Write; 11486f384573SBrian Somers 11496f384573SBrian Somers mp_linkInit(&dl->mp); 11506f384573SBrian Somers *dl->phone.list = '\0'; 11516f384573SBrian Somers dl->phone.next = NULL; 11526f384573SBrian Somers dl->phone.alt = NULL; 11536f384573SBrian Somers dl->phone.chosen = "N/A"; 11546f384573SBrian Somers 11556f384573SBrian Somers dl->bundle = bundle; 11566f384573SBrian Somers dl->next = NULL; 11576f384573SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 11586f384573SBrian Somers dl->dial_tries = 0; 11596f384573SBrian Somers dl->reconnect_tries = 0; 11606f384573SBrian Somers dl->parent = &bundle->fsm; 11616f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 11626f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 11636f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 11646f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 11656f384573SBrian Somers dl->fsmp.object = dl; 11666f384573SBrian Somers 11676f384573SBrian Somers retry = dl->pap.cfg.fsmretry; 1168dd7e2610SBrian Somers auth_Init(&dl->pap); 11696f384573SBrian Somers dl->pap.cfg.fsmretry = retry; 11706f384573SBrian Somers 11716f384573SBrian Somers retry = dl->chap.auth.cfg.fsmretry; 1172dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 11736f384573SBrian Somers dl->chap.auth.cfg.fsmretry = retry; 11746f384573SBrian Somers 117596c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 117696c9bb21SBrian Somers 117796c9bb21SBrian Somers if (!dl->physical) { 11786f384573SBrian Somers free(dl->name); 11796f384573SBrian Somers free(dl); 11806f384573SBrian Somers dl = NULL; 11819ae58882SBrian Somers } else { 118292b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 11836f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 11846f384573SBrian Somers 11859ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 11869ae58882SBrian Somers dl->name, datalink_State(dl)); 11879ae58882SBrian Somers } 11889ae58882SBrian Somers 11896f384573SBrian Somers return dl; 11906f384573SBrian Somers } 11916f384573SBrian Somers 11926f384573SBrian Somers int 119385fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 119485fd273aSBrian Somers pid_t newpid) 11956f384573SBrian Somers { 119696c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 119796c9bb21SBrian Somers int link_fd; 11986f384573SBrian Somers 119996c9bb21SBrian Somers if (dl) { 1200dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 120192b09558SBrian Somers /* The following is purely for the sake of paranoia */ 120292b09558SBrian Somers cbcp_Down(&dl->cbcp); 1203dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1204dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 12056f384573SBrian Somers } 12066f384573SBrian Somers 120796c9bb21SBrian Somers if (*niov >= maxiov - 1) { 120896c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 120996c9bb21SBrian Somers if (dl) { 12106f384573SBrian Somers free(dl->name); 12116f384573SBrian Somers free(dl); 121296c9bb21SBrian Somers } 121396c9bb21SBrian Somers return -1; 121496c9bb21SBrian Somers } 121596c9bb21SBrian Somers 121696c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 121796c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 121896c9bb21SBrian Somers iov[*niov].iov_base = 121996c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 122096c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 122196c9bb21SBrian Somers 122285fd273aSBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 122396c9bb21SBrian Somers 122496c9bb21SBrian Somers if (link_fd == -1 && dl) { 122596c9bb21SBrian Somers free(dl->name); 122696c9bb21SBrian Somers free(dl); 122796c9bb21SBrian Somers } 12286f384573SBrian Somers 12296f384573SBrian Somers return link_fd; 12306f384573SBrian Somers } 12316f384573SBrian Somers 123258d55334SBrian Somers void 123358d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 123458d55334SBrian Somers { 123558d55334SBrian Somers free(dl->name); 123658d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 123758d55334SBrian Somers } 123858d55334SBrian Somers 123984917b87SBrian Somers char * 124084917b87SBrian Somers datalink_NextName(struct datalink *dl) 12416f384573SBrian Somers { 12426f384573SBrian Somers int f, n; 124384917b87SBrian Somers char *name, *oname; 12446f384573SBrian Somers 12456f384573SBrian Somers n = strlen(dl->name); 12466f384573SBrian Somers name = (char *)malloc(n+3); 12476f384573SBrian Somers for (f = n - 1; f >= 0; f--) 12486f384573SBrian Somers if (!isdigit(dl->name[f])) 12496f384573SBrian Somers break; 12506f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 12516f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 125284917b87SBrian Somers oname = dl->name; 125354cd8e13SBrian Somers dl->name = name; 125454cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 125584917b87SBrian Somers return oname; 12566f384573SBrian Somers } 1257dd0645c5SBrian Somers 1258dd0645c5SBrian Somers int 1259dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1260dd0645c5SBrian Somers { 1261dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1262dd0645c5SBrian Somers return 0; 1263dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1264dd0645c5SBrian Somers dl->script.run = 0; 1265dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1266dd0645c5SBrian Somers dl->reconnect_tries = 0; 126781358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1268dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1269dd0645c5SBrian Somers return 1; 1270dd0645c5SBrian Somers } 1271