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 * 26eb6e5e05SBrian Somers * $Id: datalink.c,v 1.42 1999/08/05 10:32:10 brian Exp $ 273006ec67SBrian Somers */ 283006ec67SBrian Somers 29972a1bcfSBrian Somers #include <sys/param.h> 303006ec67SBrian Somers #include <netinet/in.h> 31eaa4df37SBrian Somers #include <netinet/in_systm.h> 32eaa4df37SBrian Somers #include <netinet/ip.h> 331fa665f5SBrian Somers #include <sys/un.h> 343006ec67SBrian Somers 356f384573SBrian Somers #include <ctype.h> 36c7cc5030SBrian Somers #include <stdio.h> 373006ec67SBrian Somers #include <stdlib.h> 383006ec67SBrian Somers #include <string.h> 3996c9bb21SBrian Somers #include <sys/uio.h> 403006ec67SBrian Somers #include <termios.h> 413006ec67SBrian Somers 425d9e6103SBrian Somers #include "layer.h" 433006ec67SBrian Somers #include "mbuf.h" 443006ec67SBrian Somers #include "log.h" 453006ec67SBrian Somers #include "defs.h" 463006ec67SBrian Somers #include "timer.h" 473006ec67SBrian Somers #include "fsm.h" 483006ec67SBrian Somers #include "lcp.h" 493006ec67SBrian Somers #include "descriptor.h" 50879ed6faSBrian Somers #include "lqr.h" 513006ec67SBrian Somers #include "hdlc.h" 523006ec67SBrian Somers #include "async.h" 533006ec67SBrian Somers #include "throughput.h" 543b0f8d2eSBrian Somers #include "ccp.h" 553006ec67SBrian Somers #include "link.h" 563006ec67SBrian Somers #include "physical.h" 575828db6dSBrian Somers #include "iplist.h" 58eaa4df37SBrian Somers #include "slcompress.h" 595828db6dSBrian Somers #include "ipcp.h" 605ca5389aSBrian Somers #include "filter.h" 613b0f8d2eSBrian Somers #include "mp.h" 62972a1bcfSBrian Somers #ifndef NORADIUS 63972a1bcfSBrian Somers #include "radius.h" 64972a1bcfSBrian Somers #endif 653006ec67SBrian Somers #include "bundle.h" 663006ec67SBrian Somers #include "chat.h" 67e2ebb036SBrian Somers #include "auth.h" 68c7cc5030SBrian Somers #include "prompt.h" 695d9e6103SBrian Somers #include "proto.h" 70e2ebb036SBrian Somers #include "pap.h" 71e2ebb036SBrian Somers #include "chap.h" 72565e35e5SBrian Somers #include "command.h" 7392b09558SBrian Somers #include "cbcp.h" 74e2ebb036SBrian Somers #include "datalink.h" 75c7cc5030SBrian Somers 76030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *); 779ae58882SBrian Somers static void datalink_NewState(struct datalink *, int); 783006ec67SBrian Somers 793006ec67SBrian Somers static void 803006ec67SBrian Somers datalink_OpenTimeout(void *v) 813006ec67SBrian Somers { 823006ec67SBrian Somers struct datalink *dl = (struct datalink *)v; 833006ec67SBrian Somers 84c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 853006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 86dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 873006ec67SBrian Somers } 883006ec67SBrian Somers 89b5c347a3SBrian Somers static int 903006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout) 913006ec67SBrian Somers { 92b5c347a3SBrian Somers int result = Timeout; 933006ec67SBrian Somers 94c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 953006ec67SBrian Somers if (Timeout) { 963006ec67SBrian Somers if (Timeout > 0) 97c11e57a3SBrian Somers dl->dial.timer.load = Timeout * SECTICKS; 98b5c347a3SBrian Somers else { 99b5c347a3SBrian Somers result = (random() % DIAL_TIMEOUT) + 1; 100c11e57a3SBrian Somers dl->dial.timer.load = result * SECTICKS; 101b5c347a3SBrian Somers } 102c11e57a3SBrian Somers dl->dial.timer.func = datalink_OpenTimeout; 103c11e57a3SBrian Somers dl->dial.timer.name = "dial"; 104c11e57a3SBrian Somers dl->dial.timer.arg = dl; 105c11e57a3SBrian Somers timer_Start(&dl->dial.timer); 1063006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 107dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 1083006ec67SBrian Somers dl->name, Timeout); 1093006ec67SBrian Somers } 110b5c347a3SBrian Somers return result; 1113006ec67SBrian Somers } 1123006ec67SBrian Somers 1133006ec67SBrian Somers static void 1143006ec67SBrian Somers datalink_HangupDone(struct datalink *dl) 1153006ec67SBrian Somers { 116030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 1175d9e6103SBrian Somers dl->physical->fd != -1) { 1185d9e6103SBrian Somers /* Don't close our device if the link is dedicated */ 119030e4ebbSBrian Somers datalink_LoginDone(dl); 120030e4ebbSBrian Somers return; 121030e4ebbSBrian Somers } 122030e4ebbSBrian Somers 1235d9e6103SBrian Somers physical_Close(dl->physical); 124565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1253006ec67SBrian Somers 12692b09558SBrian Somers if (dl->cbcp.required) { 12792b09558SBrian Somers log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 12892b09558SBrian Somers dl->cfg.callback.opmask = 0; 12992b09558SBrian Somers strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 13092b09558SBrian Somers sizeof dl->cfg.phone.list - 1); 13192b09558SBrian Somers dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 13292b09558SBrian Somers dl->phone.alt = dl->phone.next = NULL; 13392b09558SBrian Somers dl->reconnect_tries = dl->cfg.reconnect.max; 134c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 135c11e57a3SBrian Somers dl->dial.incs = 0; 13692b09558SBrian Somers dl->script.run = 1; 13792b09558SBrian Somers dl->script.packetmode = 1; 13892b09558SBrian Somers if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 13992b09558SBrian Somers log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 14092b09558SBrian Somers bundle_LinksRemoved(dl->bundle); 141c11e57a3SBrian Somers /* if dial.timeout is < 0 (random), we don't override fsm.delay */ 14292b09558SBrian Somers if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 14392b09558SBrian Somers dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 14492b09558SBrian Somers datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 14592b09558SBrian Somers cbcp_Down(&dl->cbcp); 14692b09558SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1470ca6f91bSBrian Somers if (bundle_Phase(dl->bundle) != PHASE_TERMINATE) 1480ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 14992b09558SBrian Somers } else if (dl->bundle->CleaningUp || 1506f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 151c11e57a3SBrian Somers ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15281358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 1539ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 154c11e57a3SBrian Somers dl->dial.tries = -1; 155c11e57a3SBrian Somers dl->dial.incs = 0; 1563006ec67SBrian Somers dl->reconnect_tries = 0; 1573006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1583b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 159c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1603006ec67SBrian Somers } else { 1619ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1620ca6f91bSBrian Somers if (bundle_Phase(dl->bundle) != PHASE_TERMINATE) 1630ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 164c11e57a3SBrian Somers if (dl->dial.tries < 0) { 165565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 166c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 167c11e57a3SBrian Somers dl->dial.incs = 0; 168abff9baeSBrian Somers dl->reconnect_tries--; 169abff9baeSBrian Somers } else { 170f9545805SBrian Somers if (dl->phone.next == NULL) 171c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1723006ec67SBrian Somers else 173565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 1743006ec67SBrian Somers } 175abff9baeSBrian Somers } 176abff9baeSBrian Somers } 1773006ec67SBrian Somers 178eb6e5e05SBrian Somers const char * 179f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 180f9545805SBrian Somers { 181f9545805SBrian Somers char *phone; 182f9545805SBrian Somers 183f9545805SBrian Somers if (dl->phone.alt == NULL) { 184f9545805SBrian Somers if (dl->phone.next == NULL) { 185f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 186f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 18708da4867SBrian Somers if (*dl->phone.list == '\0') 18808da4867SBrian Somers return ""; 189f9545805SBrian Somers dl->phone.next = dl->phone.list; 190f9545805SBrian Somers } 191f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 192f9545805SBrian Somers } 193f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 194f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 195f9545805SBrian Somers if (*phone) 196dd7e2610SBrian Somers log_Printf(LogPHASE, "Phone: %s\n", phone); 197f9545805SBrian Somers return phone; 198f9545805SBrian Somers } 199f9545805SBrian Somers 200c5a5a6caSBrian Somers static void 201c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 202c5a5a6caSBrian Somers { 203d345321bSBrian Somers if (!dl->script.packetmode) { 204c11e57a3SBrian Somers dl->dial.tries = -1; 205c11e57a3SBrian Somers dl->dial.incs = 0; 2069ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 2075d9e6103SBrian Somers } else if (!physical_Raw(dl->physical)) { 208c11e57a3SBrian Somers dl->dial.tries = 0; 209dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 210c5a5a6caSBrian Somers if (dl->script.run) { 2119ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 2125d9e6103SBrian Somers physical_Offline(dl->physical); 213f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 214030e4ebbSBrian Somers } else { 2156815097bSBrian Somers physical_StopDeviceTimer(dl->physical); 216030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 217030e4ebbSBrian Somers /* force a redial timeout */ 2185d9e6103SBrian Somers physical_Close(dl->physical); 219c5a5a6caSBrian Somers datalink_HangupDone(dl); 220030e4ebbSBrian Somers } 221c5a5a6caSBrian Somers } else { 222c11e57a3SBrian Somers dl->dial.tries = -1; 223c11e57a3SBrian Somers dl->dial.incs = 0; 224c7cc5030SBrian Somers 225643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 2263b0f8d2eSBrian Somers async_Init(&dl->physical->async); 2273b0f8d2eSBrian Somers 228cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 229cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 2303b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 231503a7782SBrian Somers 2329ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 233dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 234dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm); 235c5a5a6caSBrian Somers } 236c5a5a6caSBrian Somers } 237c5a5a6caSBrian Somers 2383006ec67SBrian Somers static int 2393006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 2403006ec67SBrian Somers int *n) 2413006ec67SBrian Somers { 2423006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2433006ec67SBrian Somers int result; 2443006ec67SBrian Somers 245310c3babSBrian Somers result = 0; 2463006ec67SBrian Somers switch (dl->state) { 2473006ec67SBrian Somers case DATALINK_CLOSED: 24881358fa3SBrian Somers if ((dl->physical->type & 24981358fa3SBrian Somers (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 250194c225dSBrian Somers !dl->bundle->CleaningUp) 251565e35e5SBrian Somers /* 25281358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 25381358fa3SBrian Somers * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 25481358fa3SBrian Somers * Go to DATALINK_OPENING via datalink_Up() and fall through. 255565e35e5SBrian Somers */ 256565e35e5SBrian Somers datalink_Up(dl, 1, 1); 257565e35e5SBrian Somers else 258310c3babSBrian Somers break; 259565e35e5SBrian Somers /* fall through */ 2603006ec67SBrian Somers 2613006ec67SBrian Somers case DATALINK_OPENING: 262c11e57a3SBrian Somers if (dl->dial.timer.state != TIMER_RUNNING) { 263c11e57a3SBrian Somers if (--dl->dial.tries < 0) 264c11e57a3SBrian Somers dl->dial.tries = 0; 2655d9e6103SBrian Somers if (physical_Open(dl->physical, dl->bundle) >= 0) { 266bf1d3ff6SBrian Somers log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 267bf1d3ff6SBrian Somers "Type `~?' for help\r\n", dl->name, 268bf1d3ff6SBrian Somers dl->physical->name.full); 269c5a5a6caSBrian Somers if (dl->script.run) { 2709ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 271f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 272eb6e5e05SBrian Somers *dl->cfg.script.dial ? 273eb6e5e05SBrian Somers datalink_ChoosePhoneNumber(dl) : ""); 27481358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 275565e35e5SBrian Somers dl->cfg.dial.max) 276dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 277c11e57a3SBrian Somers dl->name, dl->cfg.dial.max - dl->dial.tries, 278565e35e5SBrian Somers dl->cfg.dial.max); 279c5a5a6caSBrian Somers } else 280c5a5a6caSBrian Somers datalink_LoginDone(dl); 2818b09cf1cSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2823006ec67SBrian Somers } else { 28381358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 284565e35e5SBrian Somers dl->cfg.dial.max) 2855d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 286c11e57a3SBrian Somers dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 2873006ec67SBrian Somers else 2885d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device\n"); 2893006ec67SBrian Somers 2903b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 29181358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 292c11e57a3SBrian Somers dl->cfg.dial.max && dl->dial.tries == 0)) { 2939ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 2943006ec67SBrian Somers dl->reconnect_tries = 0; 295c11e57a3SBrian Somers dl->dial.tries = -1; 296bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s\n", 297bf1d3ff6SBrian Somers dl->physical->name.full); 2985b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 299c5a5a6caSBrian Somers } 300bf1d3ff6SBrian Somers if (!dl->bundle->CleaningUp) { 301c11e57a3SBrian Somers int timeout; 302c11e57a3SBrian Somers 303c11e57a3SBrian Somers timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 304bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 305b5c347a3SBrian Somers dl->physical->name.full, timeout); 3063006ec67SBrian Somers } 3073006ec67SBrian Somers } 308bf1d3ff6SBrian Somers } 309310c3babSBrian Somers break; 3103006ec67SBrian Somers 311eb6e5e05SBrian Somers case DATALINK_CARRIER: 312eb6e5e05SBrian Somers /* Wait for carrier on the device */ 313eb6e5e05SBrian Somers switch (physical_AwaitCarrier(dl->physical)) { 314eb6e5e05SBrian Somers case CARRIER_PENDING: 315eb6e5e05SBrian Somers log_Printf(LogDEBUG, "Waiting for carrier\n"); 316eb6e5e05SBrian Somers return 0; /* A device timer is running to wake us up again */ 317eb6e5e05SBrian Somers 318eb6e5e05SBrian Somers case CARRIER_OK: 319eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 320eb6e5e05SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 321eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 322eb6e5e05SBrian Somers 323eb6e5e05SBrian Somers case CARRIER_LOST: 324eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 325eb6e5e05SBrian Somers physical_Offline(dl->physical); /* Is this required ? */ 326eb6e5e05SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 327eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 328eb6e5e05SBrian Somers } 329eb6e5e05SBrian Somers 3303006ec67SBrian Somers case DATALINK_HANGUP: 3313006ec67SBrian Somers case DATALINK_DIAL: 3323006ec67SBrian Somers case DATALINK_LOGIN: 3333006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 3343006ec67SBrian Somers switch (dl->chat.state) { 3353006ec67SBrian Somers case CHAT_DONE: 3363006ec67SBrian Somers /* script succeeded */ 33739d94652SBrian Somers chat_Destroy(&dl->chat); 3383006ec67SBrian Somers switch(dl->state) { 3393006ec67SBrian Somers case DATALINK_HANGUP: 3403006ec67SBrian Somers datalink_HangupDone(dl); 3413006ec67SBrian Somers break; 3423006ec67SBrian Somers case DATALINK_DIAL: 343eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_CARRIER); 3441342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3453006ec67SBrian Somers case DATALINK_LOGIN: 34647dd77c1SBrian Somers dl->phone.alt = NULL; 347c5a5a6caSBrian Somers datalink_LoginDone(dl); 348b51a60ccSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3493006ec67SBrian Somers } 3503006ec67SBrian Somers break; 3513006ec67SBrian Somers case CHAT_FAILED: 3523006ec67SBrian Somers /* Going down - script failed */ 353dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 35439d94652SBrian Somers chat_Destroy(&dl->chat); 3553006ec67SBrian Somers switch(dl->state) { 3563006ec67SBrian Somers case DATALINK_HANGUP: 3573006ec67SBrian Somers datalink_HangupDone(dl); 3583006ec67SBrian Somers break; 3593006ec67SBrian Somers case DATALINK_DIAL: 3603006ec67SBrian Somers case DATALINK_LOGIN: 3619ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 3625d9e6103SBrian Somers physical_Offline(dl->physical); /* Is this required ? */ 363eb6e5e05SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 364eb6e5e05SBrian Somers 1, NULL); 3651342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3663006ec67SBrian Somers } 3673006ec67SBrian Somers break; 3683006ec67SBrian Somers } 3693006ec67SBrian Somers break; 370c7cc5030SBrian Somers 371c7cc5030SBrian Somers case DATALINK_READY: 372e2ebb036SBrian Somers case DATALINK_LCP: 373e2ebb036SBrian Somers case DATALINK_AUTH: 37492b09558SBrian Somers case DATALINK_CBCP: 3753006ec67SBrian Somers case DATALINK_OPEN: 37658330d7bSBrian Somers result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 37758330d7bSBrian Somers descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3783006ec67SBrian Somers break; 3793006ec67SBrian Somers } 3803006ec67SBrian Somers return result; 3813006ec67SBrian Somers } 3823006ec67SBrian Somers 383ea722969SBrian Somers int 384ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 385ea722969SBrian Somers { 386ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 387ea722969SBrian Somers } 388ea722969SBrian Somers 3893006ec67SBrian Somers static int 3902f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3913006ec67SBrian Somers { 3923006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3933006ec67SBrian Somers 3943006ec67SBrian Somers switch (dl->state) { 3953006ec67SBrian Somers case DATALINK_CLOSED: 396c7cc5030SBrian Somers case DATALINK_OPENING: 3973006ec67SBrian Somers break; 398c7cc5030SBrian Somers 3993006ec67SBrian Somers case DATALINK_HANGUP: 4003006ec67SBrian Somers case DATALINK_DIAL: 4013006ec67SBrian Somers case DATALINK_LOGIN: 4023006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 403c7cc5030SBrian Somers 404c7cc5030SBrian Somers case DATALINK_READY: 405e2ebb036SBrian Somers case DATALINK_LCP: 406e2ebb036SBrian Somers case DATALINK_AUTH: 40792b09558SBrian Somers case DATALINK_CBCP: 4083006ec67SBrian Somers case DATALINK_OPEN: 40958330d7bSBrian Somers return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 41058330d7bSBrian Somers descriptor_IsSet(&dl->physical->desc, fdset); 4113006ec67SBrian Somers } 4123006ec67SBrian Somers return 0; 4133006ec67SBrian Somers } 4143006ec67SBrian Somers 4153006ec67SBrian Somers static void 4163006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 4173006ec67SBrian Somers { 4183006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4193006ec67SBrian Somers 4203006ec67SBrian Somers switch (dl->state) { 4213006ec67SBrian Somers case DATALINK_CLOSED: 422c7cc5030SBrian Somers case DATALINK_OPENING: 4233006ec67SBrian Somers break; 424c7cc5030SBrian Somers 4253006ec67SBrian Somers case DATALINK_HANGUP: 4263006ec67SBrian Somers case DATALINK_DIAL: 4273006ec67SBrian Somers case DATALINK_LOGIN: 4283006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 4293006ec67SBrian Somers break; 430c7cc5030SBrian Somers 431c7cc5030SBrian Somers case DATALINK_READY: 432e2ebb036SBrian Somers case DATALINK_LCP: 433e2ebb036SBrian Somers case DATALINK_AUTH: 43492b09558SBrian Somers case DATALINK_CBCP: 4353006ec67SBrian Somers case DATALINK_OPEN: 43658330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 43758330d7bSBrian Somers descriptor_Read(&dl->chap.desc, bundle, fdset); 43858330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 4393006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 4403006ec67SBrian Somers break; 4413006ec67SBrian Somers } 4423006ec67SBrian Somers } 4433006ec67SBrian Somers 4441af29a6eSBrian Somers static int 445f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 4463006ec67SBrian Somers { 4473006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4481af29a6eSBrian Somers int result = 0; 4493006ec67SBrian Somers 4503006ec67SBrian Somers switch (dl->state) { 4513006ec67SBrian Somers case DATALINK_CLOSED: 452c7cc5030SBrian Somers case DATALINK_OPENING: 4533006ec67SBrian Somers break; 454c7cc5030SBrian Somers 4553006ec67SBrian Somers case DATALINK_HANGUP: 4563006ec67SBrian Somers case DATALINK_DIAL: 4573006ec67SBrian Somers case DATALINK_LOGIN: 4581af29a6eSBrian Somers result = descriptor_Write(&dl->chat.desc, bundle, fdset); 4593006ec67SBrian Somers break; 460c7cc5030SBrian Somers 461c7cc5030SBrian Somers case DATALINK_READY: 462e2ebb036SBrian Somers case DATALINK_LCP: 463e2ebb036SBrian Somers case DATALINK_AUTH: 46492b09558SBrian Somers case DATALINK_CBCP: 4653006ec67SBrian Somers case DATALINK_OPEN: 46658330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 46758330d7bSBrian Somers result += descriptor_Write(&dl->chap.desc, bundle, fdset); 46858330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 46958330d7bSBrian Somers result += descriptor_Write(&dl->physical->desc, bundle, fdset); 4703006ec67SBrian Somers break; 4713006ec67SBrian Somers } 4721af29a6eSBrian Somers 4731af29a6eSBrian Somers return result; 4743006ec67SBrian Somers } 4753006ec67SBrian Somers 4766d666775SBrian Somers static void 4779c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 478e2ebb036SBrian Somers { 4799c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 480c11e57a3SBrian Somers dl->dial.tries = -1; 481e2ebb036SBrian Somers dl->reconnect_tries = 0; 4827729a182SBrian Somers if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 4839c81b87dSBrian Somers dl->stayonline = 1; 484e2ebb036SBrian Somers } 485e2ebb036SBrian Somers 4867729a182SBrian Somers if (dl->state >= DATALINK_READY && dl->stayonline) { 4879c81b87dSBrian Somers dl->stayonline = 0; 4886815097bSBrian Somers physical_StopDeviceTimer(dl->physical); 4899c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY); 4909c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 4915d9e6103SBrian Somers physical_Offline(dl->physical); 492b6f5f442SBrian Somers chat_Destroy(&dl->chat); 493e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4949ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 495f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 496e2ebb036SBrian Somers } else 497e2ebb036SBrian Somers datalink_HangupDone(dl); 498e2ebb036SBrian Somers } 499e2ebb036SBrian Somers } 500e2ebb036SBrian Somers 501e2ebb036SBrian Somers static void 5026d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 5036d666775SBrian Somers { 5046d666775SBrian Somers /* The given FSM is about to start up ! */ 5056d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 506a611cad6SBrian Somers 50792e872e7SBrian Somers if (fp->proto == PROTO_LCP) 508e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 509e2ebb036SBrian Somers } 5106d666775SBrian Somers 5116d666775SBrian Somers static void 5126d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 5136d666775SBrian Somers { 5146d666775SBrian Somers /* The given fsm is now up */ 5156d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 5165e315498SBrian Somers struct lcp *lcp = &dl->physical->link.lcp; 5176d666775SBrian Somers 51892e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 519f0cdd9c0SBrian Somers datalink_GotAuthname(dl, ""); 5205e315498SBrian Somers lcp->auth_ineed = lcp->want_auth; 5215e315498SBrian Somers lcp->auth_iwait = lcp->his_auth; 5225e315498SBrian Somers if (lcp->his_auth || lcp->want_auth) { 5235945a079SBrian Somers if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 5245563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 525dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 5265e315498SBrian Somers Auth2Nam(lcp->his_auth, lcp->his_authtype), 5275e315498SBrian Somers Auth2Nam(lcp->want_auth, lcp->want_authtype)); 5285e315498SBrian Somers if (lcp->his_auth == PROTO_PAP) 529f0cdd9c0SBrian Somers auth_StartReq(&dl->pap); 5305e315498SBrian Somers if (lcp->want_auth == PROTO_CHAP) 531f0cdd9c0SBrian Somers auth_StartReq(&dl->chap.auth); 532e2ebb036SBrian Somers } else 533e2ebb036SBrian Somers datalink_AuthOk(dl); 534e2ebb036SBrian Somers } 535e2ebb036SBrian Somers } 536e2ebb036SBrian Somers 53764cfdfc6SBrian Somers static void 53864cfdfc6SBrian Somers datalink_AuthReInit(struct datalink *dl) 53964cfdfc6SBrian Somers { 54064cfdfc6SBrian Somers auth_StopTimer(&dl->pap); 54164cfdfc6SBrian Somers auth_StopTimer(&dl->chap.auth); 54264cfdfc6SBrian Somers chap_ReInit(&dl->chap); 54364cfdfc6SBrian Somers } 54464cfdfc6SBrian Somers 545e2ebb036SBrian Somers void 546f0cdd9c0SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name) 547643f4904SBrian Somers { 548f0cdd9c0SBrian Somers strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 549f0cdd9c0SBrian Somers dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 550643f4904SBrian Somers } 551643f4904SBrian Somers 552643f4904SBrian Somers void 55392b09558SBrian Somers datalink_NCPUp(struct datalink *dl) 554e2ebb036SBrian Somers { 55506337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 5561df0a3b9SBrian Somers 557dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 5581fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 5591fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 5601fa665f5SBrian Somers case MP_LINKSENT: 561ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 5621fa665f5SBrian Somers return; 5631fa665f5SBrian Somers case MP_UP: 5640a1b5c9dSBrian Somers /* First link in the bundle */ 56592b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 566ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 5670a1b5c9dSBrian Somers /* fall through */ 5681fa665f5SBrian Somers case MP_ADDED: 5690a1b5c9dSBrian Somers /* We're in multilink mode ! */ 5701df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 571ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 5721fa665f5SBrian Somers break; 5731fa665f5SBrian Somers case MP_FAILED: 57449052c95SBrian Somers datalink_AuthNotOk(dl); 57549052c95SBrian Somers return; 57649052c95SBrian Somers } 57749052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 578dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 579897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 580ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 581897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 58249052c95SBrian Somers return; 58350abd4c8SBrian Somers } else { 58450abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 585ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 58692b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 58750abd4c8SBrian Somers } 58849052c95SBrian Somers 58906337856SBrian Somers if (ccpok) { 590dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 591dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 59206337856SBrian Somers } 5939ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 5943b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 5953b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 5966d666775SBrian Somers } 597e2ebb036SBrian Somers 598e2ebb036SBrian Somers void 59992b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl) 60092b09558SBrian Somers { 60192b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 60264cfdfc6SBrian Somers datalink_AuthReInit(dl); 60392b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60492b09558SBrian Somers } 60592b09558SBrian Somers 60692b09558SBrian Somers void 60792b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl) 60892b09558SBrian Somers { 60992b09558SBrian Somers cbcp_Down(&dl->cbcp); 61092b09558SBrian Somers datalink_CBCPComplete(dl); 61192b09558SBrian Somers } 61292b09558SBrian Somers 61392b09558SBrian Somers void 61492b09558SBrian Somers datalink_AuthOk(struct datalink *dl) 61592b09558SBrian Somers { 6165165af6fSBrian Somers if ((dl->physical->link.lcp.his_callback.opmask & 61792b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) || 6185165af6fSBrian Somers dl->physical->link.lcp.want_callback.opmask & 6195165af6fSBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) && 6205165af6fSBrian Somers !(dl->physical->link.lcp.want_callback.opmask & 6215165af6fSBrian Somers CALLBACK_BIT(CALLBACK_AUTH))) { 6225165af6fSBrian Somers /* We must have agreed CBCP if AUTH isn't there any more */ 62392b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP); 62492b09558SBrian Somers cbcp_Up(&dl->cbcp); 62592b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) { 6265165af6fSBrian Somers /* It's not CBCP */ 62792b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 62892b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 62964cfdfc6SBrian Somers datalink_AuthReInit(dl); 63092b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 63192b09558SBrian Somers } else 63292b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) { 63392b09558SBrian Somers case 0: 63492b09558SBrian Somers datalink_NCPUp(dl); 63592b09558SBrian Somers break; 63692b09558SBrian Somers 63792b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH): 63892b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 63992b09558SBrian Somers sizeof dl->cbcp.fsm.phone); 64092b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 64192b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 64292b09558SBrian Somers dl->peer.authname); 64392b09558SBrian Somers *dl->cbcp.fsm.phone = '\0'; 64492b09558SBrian Somers } else { 64592b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ','); 64692b09558SBrian Somers if (ptr) 64792b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */ 64892b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 64992b09558SBrian Somers dl->cbcp.fsm.phone); 65092b09558SBrian Somers dl->cbcp.required = 1; 65192b09558SBrian Somers } 65292b09558SBrian Somers dl->cbcp.fsm.delay = 0; 65392b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 65464cfdfc6SBrian Somers datalink_AuthReInit(dl); 65592b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 65692b09558SBrian Somers break; 65792b09558SBrian Somers 65892b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164): 65992b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 66092b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1); 66192b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 66292b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 66392b09558SBrian Somers dl->cbcp.fsm.phone); 66492b09558SBrian Somers dl->cbcp.required = 1; 66592b09558SBrian Somers dl->cbcp.fsm.delay = 0; 66692b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 66764cfdfc6SBrian Somers datalink_AuthReInit(dl); 66892b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 66992b09558SBrian Somers break; 67092b09558SBrian Somers 67192b09558SBrian Somers default: 67292b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 67392b09558SBrian Somers dl->name); 67492b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 67564cfdfc6SBrian Somers datalink_AuthReInit(dl); 67692b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 67792b09558SBrian Somers break; 67892b09558SBrian Somers } 67992b09558SBrian Somers } 68092b09558SBrian Somers 68192b09558SBrian Somers void 682e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 683e2ebb036SBrian Somers { 6849ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 68564cfdfc6SBrian Somers datalink_AuthReInit(dl); 686dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 6876d666775SBrian Somers } 6886d666775SBrian Somers 6896d666775SBrian Somers static void 6906d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 6916d666775SBrian Somers { 6926d666775SBrian Somers /* The given FSM has been told to come down */ 6936d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 694a611cad6SBrian Somers 69592e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 696e2ebb036SBrian Somers switch (dl->state) { 697e2ebb036SBrian Somers case DATALINK_OPEN: 698643f4904SBrian Somers peerid_Init(&dl->peer); 69909206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 700ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 701e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 70292b09558SBrian Somers /* fall through (just in case) */ 70392b09558SBrian Somers 70492b09558SBrian Somers case DATALINK_CBCP: 70592b09558SBrian Somers if (!dl->cbcp.required) 70692b09558SBrian Somers cbcp_Down(&dl->cbcp); 70792b09558SBrian Somers /* fall through (just in case) */ 708e2ebb036SBrian Somers 709e2ebb036SBrian Somers case DATALINK_AUTH: 710dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 711dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 7126d666775SBrian Somers } 7139ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 71464cfdfc6SBrian Somers datalink_AuthReInit(dl); 715e2ebb036SBrian Somers } 7166d666775SBrian Somers } 7176d666775SBrian Somers 7186d666775SBrian Somers static void 7196d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 7206d666775SBrian Somers { 7216d666775SBrian Somers /* The given fsm is now down */ 7226d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 7236d666775SBrian Somers 72492e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 72509206a6fSBrian Somers fsm2initial(fp); 7266d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 7279c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 7280a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 7290a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 7306d666775SBrian Somers } 7316d666775SBrian Somers 7323006ec67SBrian Somers struct datalink * 7336f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 7343006ec67SBrian Somers { 7353006ec67SBrian Somers struct datalink *dl; 7363006ec67SBrian Somers 7373006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 7383006ec67SBrian Somers if (dl == NULL) 7393006ec67SBrian Somers return dl; 7403006ec67SBrian Somers 7413006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 7423006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 7433006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 7443006ec67SBrian Somers dl->desc.Read = datalink_Read; 7453006ec67SBrian Somers dl->desc.Write = datalink_Write; 7465b8b8060SBrian Somers 747e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 748e718d1d7SBrian Somers 74973a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 75073a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 75173a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 752f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 753f9545805SBrian Somers *dl->phone.list = '\0'; 754f9545805SBrian Somers dl->phone.next = NULL; 755f9545805SBrian Somers dl->phone.alt = NULL; 756f9545805SBrian Somers dl->phone.chosen = "N/A"; 7579c81b87dSBrian Somers dl->stayonline = 0; 758c7cc5030SBrian Somers dl->script.run = 1; 759c7cc5030SBrian Somers dl->script.packetmode = 1; 7603b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 7615b8b8060SBrian Somers 7623006ec67SBrian Somers dl->bundle = bundle; 7633006ec67SBrian Somers dl->next = NULL; 764e718d1d7SBrian Somers 765c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 766e718d1d7SBrian Somers 767c11e57a3SBrian Somers dl->dial.tries = 0; 768565e35e5SBrian Somers dl->cfg.dial.max = 1; 769565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 770565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 771c11e57a3SBrian Somers dl->cfg.dial.inc = 0; 772c11e57a3SBrian Somers dl->cfg.dial.maxinc = 10; 773e718d1d7SBrian Somers 774abff9baeSBrian Somers dl->reconnect_tries = 0; 775565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 776565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 777abff9baeSBrian Somers 77892b09558SBrian Somers dl->cfg.callback.opmask = 0; 77992b09558SBrian Somers dl->cfg.cbcp.delay = 0; 78092b09558SBrian Somers *dl->cfg.cbcp.phone = '\0'; 78192b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 78292b09558SBrian Somers 7833006ec67SBrian Somers dl->name = strdup(name); 784643f4904SBrian Somers peerid_Init(&dl->peer); 7856f384573SBrian Somers dl->parent = &bundle->fsm; 7863b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 7873b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 7883b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 7893b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 7903b0f8d2eSBrian Somers dl->fsmp.object = dl; 7913b0f8d2eSBrian Somers 7925d9e6103SBrian Somers if ((dl->physical = physical_Create(dl, type)) == NULL) { 7933006ec67SBrian Somers free(dl->name); 7943006ec67SBrian Somers free(dl); 7953006ec67SBrian Somers return NULL; 7963006ec67SBrian Somers } 797f0cdd9c0SBrian Somers 798f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 799f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 80092b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 801f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 8023006ec67SBrian Somers 8039ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 8049ae58882SBrian Somers dl->name, datalink_State(dl)); 8053006ec67SBrian Somers 8063006ec67SBrian Somers return dl; 8073006ec67SBrian Somers } 8083006ec67SBrian Somers 8093006ec67SBrian Somers struct datalink * 810cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 811cd7bd93aSBrian Somers { 812cd7bd93aSBrian Somers struct datalink *dl; 813cd7bd93aSBrian Somers 814cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 815cd7bd93aSBrian Somers if (dl == NULL) 816cd7bd93aSBrian Somers return dl; 817cd7bd93aSBrian Somers 818cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 819cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 820cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 821cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 822cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 823cd7bd93aSBrian Somers 824cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 825cd7bd93aSBrian Somers 826cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 827cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 828cd7bd93aSBrian Somers *dl->phone.list = '\0'; 829643f4904SBrian Somers dl->phone.next = NULL; 830643f4904SBrian Somers dl->phone.alt = NULL; 831643f4904SBrian Somers dl->phone.chosen = "N/A"; 832cd7bd93aSBrian Somers dl->bundle = odl->bundle; 833cd7bd93aSBrian Somers dl->next = NULL; 834c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 835c11e57a3SBrian Somers dl->dial.tries = 0; 836cd7bd93aSBrian Somers dl->reconnect_tries = 0; 837cd7bd93aSBrian Somers dl->name = strdup(name); 838643f4904SBrian Somers peerid_Init(&dl->peer); 839cd7bd93aSBrian Somers dl->parent = odl->parent; 840cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 841643f4904SBrian Somers dl->fsmp.object = dl; 842cd7bd93aSBrian Somers 8435d9e6103SBrian Somers if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { 844cd7bd93aSBrian Somers free(dl->name); 845cd7bd93aSBrian Somers free(dl); 846cd7bd93aSBrian Somers return NULL; 847cd7bd93aSBrian Somers } 848f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 849479508cfSBrian Somers dl->pap.cfg = odl->pap.cfg; 850f0cdd9c0SBrian Somers 851f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 852479508cfSBrian Somers dl->chap.auth.cfg = odl->chap.auth.cfg; 853f0cdd9c0SBrian Somers 854cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 855cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 856cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 857cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 858cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 859cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 860cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 861cd7bd93aSBrian Somers 86292b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 863cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 864cd7bd93aSBrian Somers 8659ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 8669ae58882SBrian Somers dl->name, datalink_State(dl)); 867cd7bd93aSBrian Somers 868cd7bd93aSBrian Somers return dl; 869cd7bd93aSBrian Somers } 870cd7bd93aSBrian Somers 871cd7bd93aSBrian Somers struct datalink * 8723006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 8733006ec67SBrian Somers { 8743006ec67SBrian Somers struct datalink *result; 8753006ec67SBrian Somers 87639d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 877dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 878c7cc5030SBrian Somers datalink_State(dl)); 87939d94652SBrian Somers switch (dl->state) { 88039d94652SBrian Somers case DATALINK_HANGUP: 88139d94652SBrian Somers case DATALINK_DIAL: 88239d94652SBrian Somers case DATALINK_LOGIN: 88339d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 88439d94652SBrian Somers break; 88539d94652SBrian Somers } 88639d94652SBrian Somers } 8873006ec67SBrian Somers 888c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 8893006ec67SBrian Somers result = dl->next; 8905d9e6103SBrian Somers physical_Destroy(dl->physical); 8913006ec67SBrian Somers free(dl->name); 8923006ec67SBrian Somers free(dl); 8933006ec67SBrian Somers 8943006ec67SBrian Somers return result; 8953006ec67SBrian Somers } 8963006ec67SBrian Somers 8973006ec67SBrian Somers void 898c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 8993006ec67SBrian Somers { 9006f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 901565e35e5SBrian Somers /* Ignore scripts */ 902565e35e5SBrian Somers runscripts = 0; 903565e35e5SBrian Somers 904c7cc5030SBrian Somers switch (dl->state) { 905c7cc5030SBrian Somers case DATALINK_CLOSED: 9063b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 9073b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 9083b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 9099ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 910565e35e5SBrian Somers dl->reconnect_tries = 9116f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 912c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 913c5a5a6caSBrian Somers dl->script.run = runscripts; 914c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 915c7cc5030SBrian Somers break; 916c7cc5030SBrian Somers 917c7cc5030SBrian Somers case DATALINK_OPENING: 918c7cc5030SBrian Somers if (!dl->script.run && runscripts) 919c7cc5030SBrian Somers dl->script.run = 1; 920c7cc5030SBrian Somers /* fall through */ 921c7cc5030SBrian Somers 922c7cc5030SBrian Somers case DATALINK_DIAL: 923c7cc5030SBrian Somers case DATALINK_LOGIN: 924c7cc5030SBrian Somers case DATALINK_READY: 925c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 926c7cc5030SBrian Somers dl->script.packetmode = 1; 927c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 928c7cc5030SBrian Somers datalink_LoginDone(dl); 929c7cc5030SBrian Somers } 930c7cc5030SBrian Somers break; 9313006ec67SBrian Somers } 9323006ec67SBrian Somers } 9333006ec67SBrian Somers 9343006ec67SBrian Somers void 9359c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 936c7cc5030SBrian Somers { 937c7cc5030SBrian Somers /* Please close */ 938e2ebb036SBrian Somers switch (dl->state) { 939e2ebb036SBrian Somers case DATALINK_OPEN: 940643f4904SBrian Somers peerid_Init(&dl->peer); 94109206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 942e2ebb036SBrian Somers /* fall through */ 943e2ebb036SBrian Somers 94492b09558SBrian Somers case DATALINK_CBCP: 945e2ebb036SBrian Somers case DATALINK_AUTH: 946e2ebb036SBrian Somers case DATALINK_LCP: 94764cfdfc6SBrian Somers datalink_AuthReInit(dl); 948dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 9499c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 950c11e57a3SBrian Somers dl->dial.tries = -1; 951c7cc5030SBrian Somers dl->reconnect_tries = 0; 9529c81b87dSBrian Somers if (how == CLOSE_LCP) 9539c81b87dSBrian Somers dl->stayonline = 1; 954c7cc5030SBrian Somers } 955e2ebb036SBrian Somers break; 956e2ebb036SBrian Somers 957e2ebb036SBrian Somers default: 9589c81b87dSBrian Somers datalink_ComeDown(dl, how); 959c7cc5030SBrian Somers } 960e2ebb036SBrian Somers } 961c7cc5030SBrian Somers 962c7cc5030SBrian Somers void 9639c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 964c7cc5030SBrian Somers { 965c7cc5030SBrian Somers /* Carrier is lost */ 966e2ebb036SBrian Somers switch (dl->state) { 967e2ebb036SBrian Somers case DATALINK_OPEN: 968643f4904SBrian Somers peerid_Init(&dl->peer); 96909206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 970e2ebb036SBrian Somers /* fall through */ 971e2ebb036SBrian Somers 97292b09558SBrian Somers case DATALINK_CBCP: 973e2ebb036SBrian Somers case DATALINK_AUTH: 974e2ebb036SBrian Somers case DATALINK_LCP: 97509206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 976e2ebb036SBrian Somers /* fall through */ 977c7cc5030SBrian Somers 978e2ebb036SBrian Somers default: 9799c81b87dSBrian Somers datalink_ComeDown(dl, how); 980c7cc5030SBrian Somers } 981e2ebb036SBrian Somers } 982c7cc5030SBrian Somers 983c7cc5030SBrian Somers void 9843006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 9853006ec67SBrian Somers { 9863006ec67SBrian Somers dl->reconnect_tries = 0; 9873006ec67SBrian Somers } 988c7cc5030SBrian Somers 9899c81b87dSBrian Somers void 9909c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 9919c81b87dSBrian Somers { 9927729a182SBrian Somers if (dl->state >= DATALINK_LCP) 9939c81b87dSBrian Somers dl->stayonline = 1; 9949c81b87dSBrian Somers } 9959c81b87dSBrian Somers 996643f4904SBrian Somers int 997643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 998c7cc5030SBrian Somers { 999643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 1000643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 1001643f4904SBrian Somers datalink_State(arg->cx)); 1002643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 1003643f4904SBrian Somers if (*arg->cx->peer.authname) 1004643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 1005643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 1006643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 1007565e35e5SBrian Somers else 1008643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 1009643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 1010643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 1011643f4904SBrian Somers arg->cx->peer.enddisc.address, 1012643f4904SBrian Somers arg->cx->peer.enddisc.len)); 1013643f4904SBrian Somers 1014643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 1015643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 1016643f4904SBrian Somers arg->cx->cfg.phone.list); 1017643f4904SBrian Somers if (arg->cx->cfg.dial.max) 1018643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 1019643f4904SBrian Somers arg->cx->cfg.dial.max); 1020565e35e5SBrian Somers else 1021643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 1022b5c347a3SBrian Somers if (arg->cx->cfg.dial.next_timeout >= 0) 1023643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 1024565e35e5SBrian Somers else 1025643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 1026b5c347a3SBrian Somers if (arg->cx->cfg.dial.timeout >= 0) 1027643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 1028565e35e5SBrian Somers else 1029643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 1030643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 1031643f4904SBrian Somers arg->cx->cfg.reconnect.max); 1032643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 1033643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 1034643f4904SBrian Somers else 1035643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 103692b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 103792b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 103892b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 103992b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 104092b09558SBrian Somers else { 104192b09558SBrian Somers int comma = 0; 104292b09558SBrian Somers 104392b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 104492b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 104592b09558SBrian Somers comma = 1; 104692b09558SBrian Somers } 104792b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 104892b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 104992b09558SBrian Somers comma = 1; 105092b09558SBrian Somers } 105192b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 105292b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 105392b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 105492b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 105592b09558SBrian Somers comma = 1; 105692b09558SBrian Somers } 105792b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 105892b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 105992b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 106092b09558SBrian Somers arg->cx->cfg.cbcp.delay); 1061cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: "); 1062cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 1063cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT) 1064cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n"); 1065cf784a89SBrian Somers else 1066cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n"); 1067cf784a89SBrian Somers } else 1068cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 106992b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 107092b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 107192b09558SBrian Somers } else 107292b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 107392b09558SBrian Somers } 107492b09558SBrian Somers 1075643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 1076643f4904SBrian Somers arg->cx->cfg.script.dial); 1077643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 1078643f4904SBrian Somers arg->cx->cfg.script.login); 1079643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1080643f4904SBrian Somers arg->cx->cfg.script.hangup); 1081643f4904SBrian Somers return 0; 1082565e35e5SBrian Somers } 1083565e35e5SBrian Somers 1084565e35e5SBrian Somers int 1085565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1086565e35e5SBrian Somers { 108725092092SBrian Somers if (arg->argc == arg->argn+2) { 108825092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 108925092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1090565e35e5SBrian Somers return 0; 1091565e35e5SBrian Somers } 1092565e35e5SBrian Somers return -1; 1093565e35e5SBrian Somers } 1094565e35e5SBrian Somers 1095565e35e5SBrian Somers int 1096565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1097565e35e5SBrian Somers { 1098c11e57a3SBrian Somers const char *sep, *osep; 1099c11e57a3SBrian Somers int timeout, inc, maxinc, tries; 1100565e35e5SBrian Somers 110125092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 110225092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 110325092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1104565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1105565e35e5SBrian Somers randinit(); 1106565e35e5SBrian Somers } else { 110725092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1108565e35e5SBrian Somers 1109565e35e5SBrian Somers if (timeout >= 0) 1110565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1111565e35e5SBrian Somers else { 1112dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1113565e35e5SBrian Somers return -1; 1114565e35e5SBrian Somers } 1115565e35e5SBrian Somers } 1116565e35e5SBrian Somers 1117c11e57a3SBrian Somers sep = strchr(arg->argv[arg->argn], '+'); 1118c11e57a3SBrian Somers if (sep) { 1119c11e57a3SBrian Somers inc = atoi(++sep); 1120c11e57a3SBrian Somers osep = sep; 1121c11e57a3SBrian Somers if (inc >= 0) 1122c11e57a3SBrian Somers arg->cx->cfg.dial.inc = inc; 1123c11e57a3SBrian Somers else { 1124c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid timeout increment\n"); 1125c11e57a3SBrian Somers return -1; 1126c11e57a3SBrian Somers } 1127c11e57a3SBrian Somers sep = strchr(sep, '-'); 1128c11e57a3SBrian Somers if (sep) { 1129c11e57a3SBrian Somers maxinc = atoi(++sep); 1130c11e57a3SBrian Somers if (maxinc >= 0) 1131c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = maxinc; 1132c11e57a3SBrian Somers else { 1133c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 1134c11e57a3SBrian Somers return -1; 1135c11e57a3SBrian Somers } 1136c11e57a3SBrian Somers } else { 1137c11e57a3SBrian Somers /* Default timeout increment */ 1138c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1139c11e57a3SBrian Somers sep = osep; 1140c11e57a3SBrian Somers } 1141c11e57a3SBrian Somers } else { 1142c11e57a3SBrian Somers /* Default timeout increment & max increment */ 1143c11e57a3SBrian Somers arg->cx->cfg.dial.inc = 0; 1144c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1145c11e57a3SBrian Somers sep = arg->argv[arg->argn]; 1146c11e57a3SBrian Somers } 1147c11e57a3SBrian Somers 1148c11e57a3SBrian Somers sep = strchr(sep, '.'); 1149c11e57a3SBrian Somers if (sep) { 1150c11e57a3SBrian Somers if (strcasecmp(++sep, "random") == 0) { 1151565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1152565e35e5SBrian Somers randinit(); 1153565e35e5SBrian Somers } else { 1154c11e57a3SBrian Somers timeout = atoi(sep); 1155565e35e5SBrian Somers if (timeout >= 0) 1156565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1157565e35e5SBrian Somers else { 1158dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1159565e35e5SBrian Somers return -1; 1160565e35e5SBrian Somers } 1161565e35e5SBrian Somers } 1162565e35e5SBrian Somers } else 1163565e35e5SBrian Somers /* Default next timeout */ 1164565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1165565e35e5SBrian Somers 116625092092SBrian Somers if (arg->argc == arg->argn+2) { 116725092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1168565e35e5SBrian Somers 1169565e35e5SBrian Somers if (tries >= 0) { 1170565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1171565e35e5SBrian Somers } else { 1172dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1173565e35e5SBrian Somers return 1; 1174565e35e5SBrian Somers } 1175565e35e5SBrian Somers } 1176565e35e5SBrian Somers return 0; 1177565e35e5SBrian Somers } 1178c11e57a3SBrian Somers 1179565e35e5SBrian Somers return -1; 1180c7cc5030SBrian Somers } 1181c7cc5030SBrian Somers 1182cdbbb6b5SBrian Somers static const char *states[] = { 1183565e35e5SBrian Somers "closed", 1184565e35e5SBrian Somers "opening", 1185565e35e5SBrian Somers "hangup", 1186565e35e5SBrian Somers "dial", 1187eb6e5e05SBrian Somers "carrier", 1188565e35e5SBrian Somers "login", 1189565e35e5SBrian Somers "ready", 1190565e35e5SBrian Somers "lcp", 1191565e35e5SBrian Somers "auth", 119292b09558SBrian Somers "cbcp", 1193565e35e5SBrian Somers "open" 1194c7cc5030SBrian Somers }; 1195c7cc5030SBrian Somers 1196643f4904SBrian Somers const char * 1197c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1198c7cc5030SBrian Somers { 1199c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1200c7cc5030SBrian Somers return "unknown"; 1201c7cc5030SBrian Somers return states[dl->state]; 1202c7cc5030SBrian Somers } 12036f384573SBrian Somers 12049ae58882SBrian Somers static void 12059ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 12069ae58882SBrian Somers { 12079ae58882SBrian Somers if (state != dl->state) { 12089ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 12099ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 12109ae58882SBrian Somers states[state]); 12119ae58882SBrian Somers dl->state = state; 12129ae58882SBrian Somers } else 12139ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 12149ae58882SBrian Somers } 12159ae58882SBrian Somers } 12169ae58882SBrian Somers 12176f384573SBrian Somers struct datalink * 121896c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 121996c9bb21SBrian Somers int fd) 12206f384573SBrian Somers { 1221b7c5748eSBrian Somers struct datalink *dl, *cdl; 1222479508cfSBrian Somers struct fsm_retry copy; 1223b7c5748eSBrian Somers char *oname; 12246f384573SBrian Somers 122596c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 122696c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 12276f384573SBrian Somers 122896c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 122996c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 123096c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 123196c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 12326f384573SBrian Somers } 1233b7c5748eSBrian Somers 1234b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1235b7c5748eSBrian Somers oname = NULL; 1236b7c5748eSBrian Somers do { 1237b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1238b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1239b7c5748eSBrian Somers if (oname) 1240b7c5748eSBrian Somers free(datalink_NextName(dl)); 1241b7c5748eSBrian Somers else 1242b7c5748eSBrian Somers oname = datalink_NextName(dl); 1243b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1244b7c5748eSBrian Somers } 1245b7c5748eSBrian Somers } while (cdl); 1246b7c5748eSBrian Somers 1247b7c5748eSBrian Somers if (oname) { 1248b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1249b7c5748eSBrian Somers free(oname); 1250b7c5748eSBrian Somers } else { 125196c9bb21SBrian Somers dl->name = strdup(dl->name); 1252b7c5748eSBrian Somers free(iov[*niov].iov_base); 1253b7c5748eSBrian Somers } 1254b7c5748eSBrian Somers (*niov)++; 12556f384573SBrian Somers 12566f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 12576f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 12586f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 12596f384573SBrian Somers dl->desc.Read = datalink_Read; 12606f384573SBrian Somers dl->desc.Write = datalink_Write; 12616f384573SBrian Somers 12626f384573SBrian Somers mp_linkInit(&dl->mp); 12636f384573SBrian Somers *dl->phone.list = '\0'; 12646f384573SBrian Somers dl->phone.next = NULL; 12656f384573SBrian Somers dl->phone.alt = NULL; 12666f384573SBrian Somers dl->phone.chosen = "N/A"; 12676f384573SBrian Somers 12686f384573SBrian Somers dl->bundle = bundle; 12696f384573SBrian Somers dl->next = NULL; 1270c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 1271c11e57a3SBrian Somers dl->dial.tries = 0; 12726f384573SBrian Somers dl->reconnect_tries = 0; 12736f384573SBrian Somers dl->parent = &bundle->fsm; 12746f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 12756f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 12766f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 12776f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 12786f384573SBrian Somers dl->fsmp.object = dl; 12796f384573SBrian Somers 12805d9e6103SBrian Somers dl->physical = iov2physical(dl, iov, niov, maxiov, fd); 128196c9bb21SBrian Somers 128296c9bb21SBrian Somers if (!dl->physical) { 12836f384573SBrian Somers free(dl->name); 12846f384573SBrian Somers free(dl); 12856f384573SBrian Somers dl = NULL; 12869ae58882SBrian Somers } else { 1287479508cfSBrian Somers copy = dl->pap.cfg.fsm; 1288f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 1289479508cfSBrian Somers dl->pap.cfg.fsm = copy; 1290f0cdd9c0SBrian Somers 1291479508cfSBrian Somers copy = dl->chap.auth.cfg.fsm; 1292f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 1293479508cfSBrian Somers dl->chap.auth.cfg.fsm = copy; 1294f0cdd9c0SBrian Somers 129592b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 12966f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 12976f384573SBrian Somers 12989ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 12999ae58882SBrian Somers dl->name, datalink_State(dl)); 13009ae58882SBrian Somers } 13019ae58882SBrian Somers 13026f384573SBrian Somers return dl; 13036f384573SBrian Somers } 13046f384573SBrian Somers 13056f384573SBrian Somers int 130685fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 130785fd273aSBrian Somers pid_t newpid) 13086f384573SBrian Somers { 130996c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 131096c9bb21SBrian Somers int link_fd; 13116f384573SBrian Somers 131296c9bb21SBrian Somers if (dl) { 1313c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 131492b09558SBrian Somers /* The following is purely for the sake of paranoia */ 131592b09558SBrian Somers cbcp_Down(&dl->cbcp); 1316dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1317dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 13186f384573SBrian Somers } 13196f384573SBrian Somers 132096c9bb21SBrian Somers if (*niov >= maxiov - 1) { 132196c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 132296c9bb21SBrian Somers if (dl) { 13236f384573SBrian Somers free(dl->name); 13246f384573SBrian Somers free(dl); 132596c9bb21SBrian Somers } 132696c9bb21SBrian Somers return -1; 132796c9bb21SBrian Somers } 132896c9bb21SBrian Somers 132996c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 133096c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 133196c9bb21SBrian Somers iov[*niov].iov_base = 133296c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 133396c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 133496c9bb21SBrian Somers 13355d9e6103SBrian Somers link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 133696c9bb21SBrian Somers 133796c9bb21SBrian Somers if (link_fd == -1 && dl) { 133896c9bb21SBrian Somers free(dl->name); 133996c9bb21SBrian Somers free(dl); 134096c9bb21SBrian Somers } 13416f384573SBrian Somers 13426f384573SBrian Somers return link_fd; 13436f384573SBrian Somers } 13446f384573SBrian Somers 134558d55334SBrian Somers void 134658d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 134758d55334SBrian Somers { 134858d55334SBrian Somers free(dl->name); 134958d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 135058d55334SBrian Somers } 135158d55334SBrian Somers 135284917b87SBrian Somers char * 135384917b87SBrian Somers datalink_NextName(struct datalink *dl) 13546f384573SBrian Somers { 13556f384573SBrian Somers int f, n; 135684917b87SBrian Somers char *name, *oname; 13576f384573SBrian Somers 13586f384573SBrian Somers n = strlen(dl->name); 13596f384573SBrian Somers name = (char *)malloc(n+3); 13606f384573SBrian Somers for (f = n - 1; f >= 0; f--) 13616f384573SBrian Somers if (!isdigit(dl->name[f])) 13626f384573SBrian Somers break; 13636f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 13646f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 136584917b87SBrian Somers oname = dl->name; 136654cd8e13SBrian Somers dl->name = name; 136754cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 136884917b87SBrian Somers return oname; 13696f384573SBrian Somers } 1370dd0645c5SBrian Somers 1371dd0645c5SBrian Somers int 1372dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1373dd0645c5SBrian Somers { 1374dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1375dd0645c5SBrian Somers return 0; 1376dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1377dd0645c5SBrian Somers dl->script.run = 0; 1378dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1379dd0645c5SBrian Somers dl->reconnect_tries = 0; 138081358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1381dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1382dd0645c5SBrian Somers return 1; 1383dd0645c5SBrian Somers } 1384c11e57a3SBrian Somers 1385c11e57a3SBrian Somers int 1386c11e57a3SBrian Somers datalink_GetDialTimeout(struct datalink *dl) 1387c11e57a3SBrian Somers { 1388c11e57a3SBrian Somers int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 1389c11e57a3SBrian Somers 1390c11e57a3SBrian Somers if (dl->dial.incs < dl->cfg.dial.maxinc) 1391c11e57a3SBrian Somers dl->dial.incs++; 1392c11e57a3SBrian Somers 1393c11e57a3SBrian Somers return result; 1394c11e57a3SBrian Somers } 1395