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 * 2697d92980SPeter Wemm * $FreeBSD$ 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 "descriptor.h" 49879ed6faSBrian Somers #include "lqr.h" 503006ec67SBrian Somers #include "hdlc.h" 511038894eSBrian Somers #include "lcp.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) 86b42135deSBrian Somers log_Printf(LogCHAT, "%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) { 96a65be227SBrian Somers if (Timeout < 0) 97b5c347a3SBrian Somers result = (random() % DIAL_TIMEOUT) + 1; 98c11e57a3SBrian Somers dl->dial.timer.load = result * SECTICKS; 99c11e57a3SBrian Somers dl->dial.timer.func = datalink_OpenTimeout; 100c11e57a3SBrian Somers dl->dial.timer.name = "dial"; 101c11e57a3SBrian Somers dl->dial.timer.arg = dl; 102c11e57a3SBrian Somers timer_Start(&dl->dial.timer); 1033006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 104dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 105a65be227SBrian Somers dl->name, result); 1063006ec67SBrian Somers } 107b5c347a3SBrian Somers return result; 1083006ec67SBrian Somers } 1093006ec67SBrian Somers 1103006ec67SBrian Somers static void 1113006ec67SBrian Somers datalink_HangupDone(struct datalink *dl) 1123006ec67SBrian Somers { 113030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 1145d9e6103SBrian Somers dl->physical->fd != -1) { 1155d9e6103SBrian Somers /* Don't close our device if the link is dedicated */ 116030e4ebbSBrian Somers datalink_LoginDone(dl); 117030e4ebbSBrian Somers return; 118030e4ebbSBrian Somers } 119030e4ebbSBrian Somers 120ffcfaec7SBrian Somers chat_Finish(&dl->chat); 1215d9e6103SBrian Somers physical_Close(dl->physical); 122565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1233006ec67SBrian Somers 12492b09558SBrian Somers if (dl->cbcp.required) { 12592b09558SBrian Somers log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 12692b09558SBrian Somers dl->cfg.callback.opmask = 0; 12792b09558SBrian Somers strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 12892b09558SBrian Somers sizeof dl->cfg.phone.list - 1); 12992b09558SBrian Somers dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 13092b09558SBrian Somers dl->phone.alt = dl->phone.next = NULL; 13192b09558SBrian Somers dl->reconnect_tries = dl->cfg.reconnect.max; 132c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 133c11e57a3SBrian Somers dl->dial.incs = 0; 13492b09558SBrian Somers dl->script.run = 1; 13592b09558SBrian Somers dl->script.packetmode = 1; 13692b09558SBrian Somers if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 13792b09558SBrian Somers log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 13892b09558SBrian Somers bundle_LinksRemoved(dl->bundle); 139c11e57a3SBrian Somers /* if dial.timeout is < 0 (random), we don't override fsm.delay */ 14092b09558SBrian Somers if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 14192b09558SBrian Somers dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 14292b09558SBrian Somers datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 14392b09558SBrian Somers cbcp_Down(&dl->cbcp); 14492b09558SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1451b02dfb4SBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 1461b02dfb4SBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 1470ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 14892b09558SBrian Somers } else if (dl->bundle->CleaningUp || 1496f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 150c11e57a3SBrian Somers ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15181358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 1529ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 153c11e57a3SBrian Somers dl->dial.tries = -1; 154c11e57a3SBrian Somers dl->dial.incs = 0; 1553006ec67SBrian Somers dl->reconnect_tries = 0; 1563006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1574b567bf2SBrian Somers if (!dl->bundle->CleaningUp && 1584b567bf2SBrian Somers !(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND))) 159c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1603006ec67SBrian Somers } else { 1619ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1621b02dfb4SBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 1631b02dfb4SBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 1640ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 165c11e57a3SBrian Somers if (dl->dial.tries < 0) { 166565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 167c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 168c11e57a3SBrian Somers dl->dial.incs = 0; 169abff9baeSBrian Somers dl->reconnect_tries--; 170b42135deSBrian Somers log_Printf(LogCHAT, "%s: Reconnect try %d of %d\n", 171b42135deSBrian Somers dl->name, dl->cfg.reconnect.max - dl->reconnect_tries, 172b42135deSBrian Somers dl->cfg.reconnect.max); 173b42135deSBrian Somers bundle_Notify(dl->bundle, EX_RECONNECT); 174abff9baeSBrian Somers } else { 175f9545805SBrian Somers if (dl->phone.next == NULL) 176c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1773006ec67SBrian Somers else 178565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 179b42135deSBrian Somers bundle_Notify(dl->bundle, EX_REDIAL); 1803006ec67SBrian Somers } 181abff9baeSBrian Somers } 182abff9baeSBrian Somers } 1833006ec67SBrian Somers 184eb6e5e05SBrian Somers const char * 185f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 186f9545805SBrian Somers { 187f9545805SBrian Somers char *phone; 188f9545805SBrian Somers 189f9545805SBrian Somers if (dl->phone.alt == NULL) { 190f9545805SBrian Somers if (dl->phone.next == NULL) { 191f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 192f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 19308da4867SBrian Somers if (*dl->phone.list == '\0') 19408da4867SBrian Somers return ""; 195f9545805SBrian Somers dl->phone.next = dl->phone.list; 196f9545805SBrian Somers } 197f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 198f9545805SBrian Somers } 199f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 200f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 201f9545805SBrian Somers if (*phone) 202b42135deSBrian Somers log_Printf(LogCHAT, "Phone: %s\n", phone); 203f9545805SBrian Somers return phone; 204f9545805SBrian Somers } 205f9545805SBrian Somers 206c5a5a6caSBrian Somers static void 207c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 208c5a5a6caSBrian Somers { 209ffcfaec7SBrian Somers chat_Finish(&dl->chat); 210c116e0c0SBrian Somers 211d345321bSBrian Somers if (!dl->script.packetmode) { 212c11e57a3SBrian Somers dl->dial.tries = -1; 213c11e57a3SBrian Somers dl->dial.incs = 0; 2149ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 2155d9e6103SBrian Somers } else if (!physical_Raw(dl->physical)) { 216c11e57a3SBrian Somers dl->dial.tries = 0; 217dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 218c5a5a6caSBrian Somers if (dl->script.run) { 219c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_LOGOUT); 220c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 221c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid logout script\n"); 222030e4ebbSBrian Somers } else { 2236815097bSBrian Somers physical_StopDeviceTimer(dl->physical); 224030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 225030e4ebbSBrian Somers /* force a redial timeout */ 2265d9e6103SBrian Somers physical_Close(dl->physical); 227c5a5a6caSBrian Somers datalink_HangupDone(dl); 228030e4ebbSBrian Somers } 229c5a5a6caSBrian Somers } else { 230c11e57a3SBrian Somers dl->dial.tries = -1; 231c11e57a3SBrian Somers dl->dial.incs = 0; 232c7cc5030SBrian Somers 233643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 2343b0f8d2eSBrian Somers async_Init(&dl->physical->async); 2353b0f8d2eSBrian Somers 236cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 237cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 2383b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 239503a7782SBrian Somers 2409ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 241dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 242dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm); 243c5a5a6caSBrian Somers } 244c5a5a6caSBrian Somers } 245c5a5a6caSBrian Somers 2463006ec67SBrian Somers static int 247f013f33eSBrian Somers datalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, 2483006ec67SBrian Somers int *n) 2493006ec67SBrian Somers { 2503006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2513006ec67SBrian Somers int result; 2523006ec67SBrian Somers 253310c3babSBrian Somers result = 0; 2543006ec67SBrian Somers switch (dl->state) { 2553006ec67SBrian Somers case DATALINK_CLOSED: 256f6a4e748SBrian Somers if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND| 257f6a4e748SBrian Somers PHYS_FOREGROUND|PHYS_DDIAL)) && 258194c225dSBrian Somers !dl->bundle->CleaningUp) 259565e35e5SBrian Somers /* 26081358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 261f6a4e748SBrian Somers * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter 262f6a4e748SBrian Somers * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up() 263f6a4e748SBrian Somers * and fall through. 264565e35e5SBrian Somers */ 265565e35e5SBrian Somers datalink_Up(dl, 1, 1); 266565e35e5SBrian Somers else 267310c3babSBrian Somers break; 268565e35e5SBrian Somers /* fall through */ 2693006ec67SBrian Somers 2703006ec67SBrian Somers case DATALINK_OPENING: 271c11e57a3SBrian Somers if (dl->dial.timer.state != TIMER_RUNNING) { 272c11e57a3SBrian Somers if (--dl->dial.tries < 0) 273c11e57a3SBrian Somers dl->dial.tries = 0; 2745d9e6103SBrian Somers if (physical_Open(dl->physical, dl->bundle) >= 0) { 275bf1d3ff6SBrian Somers log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 276bf1d3ff6SBrian Somers "Type `~?' for help\r\n", dl->name, 277bf1d3ff6SBrian Somers dl->physical->name.full); 278c5a5a6caSBrian Somers if (dl->script.run) { 2799ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 280c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.dial, 281c39aa54eSBrian Somers *dl->cfg.script.dial ? 282c39aa54eSBrian Somers datalink_ChoosePhoneNumber(dl) : "")) 283c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid dial script\n"); 28481358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 285565e35e5SBrian Somers dl->cfg.dial.max) 286dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 287c11e57a3SBrian Somers dl->name, dl->cfg.dial.max - dl->dial.tries, 288565e35e5SBrian Somers dl->cfg.dial.max); 289c5a5a6caSBrian Somers } else 29014e34a55SBrian Somers datalink_NewState(dl, DATALINK_CARRIER); 2918b09cf1cSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2923006ec67SBrian Somers } else { 29381358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 294565e35e5SBrian Somers dl->cfg.dial.max) 2955d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 296c11e57a3SBrian Somers dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 2973006ec67SBrian Somers else 2985d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device\n"); 2993006ec67SBrian Somers 3003b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 30181358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 302c11e57a3SBrian Somers dl->cfg.dial.max && dl->dial.tries == 0)) { 3039ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 3043006ec67SBrian Somers dl->reconnect_tries = 0; 305c11e57a3SBrian Somers dl->dial.tries = -1; 306bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s\n", 307bf1d3ff6SBrian Somers dl->physical->name.full); 3085b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 309c5a5a6caSBrian Somers } 310bf1d3ff6SBrian Somers if (!dl->bundle->CleaningUp) { 311c11e57a3SBrian Somers int timeout; 312c11e57a3SBrian Somers 313c11e57a3SBrian Somers timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 314b42135deSBrian Somers bundle_Notify(dl->bundle, EX_REDIAL); 315bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 316b5c347a3SBrian Somers dl->physical->name.full, timeout); 3173006ec67SBrian Somers } 3183006ec67SBrian Somers } 319bf1d3ff6SBrian Somers } 320310c3babSBrian Somers break; 3213006ec67SBrian Somers 322eb6e5e05SBrian Somers case DATALINK_CARRIER: 323eb6e5e05SBrian Somers /* Wait for carrier on the device */ 324eb6e5e05SBrian Somers switch (physical_AwaitCarrier(dl->physical)) { 325eb6e5e05SBrian Somers case CARRIER_PENDING: 326eb6e5e05SBrian Somers log_Printf(LogDEBUG, "Waiting for carrier\n"); 327eb6e5e05SBrian Somers return 0; /* A device timer is running to wake us up again */ 328eb6e5e05SBrian Somers 329eb6e5e05SBrian Somers case CARRIER_OK: 33014e34a55SBrian Somers if (dl->script.run) { 331eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 332c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL)) 333c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid login script\n"); 33414e34a55SBrian Somers } else 33514e34a55SBrian Somers datalink_LoginDone(dl); 336eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 337eb6e5e05SBrian Somers 338eb6e5e05SBrian Somers case CARRIER_LOST: 339eb6e5e05SBrian Somers physical_Offline(dl->physical); /* Is this required ? */ 34014e34a55SBrian Somers if (dl->script.run) { 34114e34a55SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 342c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 343c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n"); 344eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 345da8b7034SBrian Somers } else { 346da8b7034SBrian Somers datalink_HangupDone(dl); 347da8b7034SBrian Somers return 0; /* Maybe bundle_CleanDatalinks() has something to do */ 348da8b7034SBrian Somers } 349eb6e5e05SBrian Somers } 350eb6e5e05SBrian Somers 3513006ec67SBrian Somers case DATALINK_HANGUP: 3523006ec67SBrian Somers case DATALINK_DIAL: 353c116e0c0SBrian Somers case DATALINK_LOGOUT: 3543006ec67SBrian Somers case DATALINK_LOGIN: 3553006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 3563006ec67SBrian Somers switch (dl->chat.state) { 3573006ec67SBrian Somers case CHAT_DONE: 3583006ec67SBrian Somers /* script succeeded */ 3593006ec67SBrian Somers switch(dl->state) { 3603006ec67SBrian Somers case DATALINK_HANGUP: 3613006ec67SBrian Somers datalink_HangupDone(dl); 3623006ec67SBrian Somers break; 3633006ec67SBrian Somers case DATALINK_DIAL: 364eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_CARRIER); 3651342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 366c116e0c0SBrian Somers case DATALINK_LOGOUT: 367c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 368c116e0c0SBrian Somers physical_Offline(dl->physical); 369c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 370c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n"); 371c116e0c0SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3723006ec67SBrian Somers case DATALINK_LOGIN: 37347dd77c1SBrian Somers dl->phone.alt = NULL; 374c5a5a6caSBrian Somers datalink_LoginDone(dl); 375b51a60ccSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3763006ec67SBrian Somers } 3773006ec67SBrian Somers break; 3783006ec67SBrian Somers case CHAT_FAILED: 3793006ec67SBrian Somers /* Going down - script failed */ 380dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 3813006ec67SBrian Somers switch(dl->state) { 3823006ec67SBrian Somers case DATALINK_HANGUP: 3833006ec67SBrian Somers datalink_HangupDone(dl); 3843006ec67SBrian Somers break; 3853006ec67SBrian Somers case DATALINK_DIAL: 386c116e0c0SBrian Somers case DATALINK_LOGOUT: 3873006ec67SBrian Somers case DATALINK_LOGIN: 3889ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 389c116e0c0SBrian Somers physical_Offline(dl->physical); 390c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 391c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n"); 3921342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3933006ec67SBrian Somers } 3943006ec67SBrian Somers break; 3953006ec67SBrian Somers } 3963006ec67SBrian Somers break; 397c7cc5030SBrian Somers 398c7cc5030SBrian Somers case DATALINK_READY: 399e2ebb036SBrian Somers case DATALINK_LCP: 400e2ebb036SBrian Somers case DATALINK_AUTH: 40192b09558SBrian Somers case DATALINK_CBCP: 4023006ec67SBrian Somers case DATALINK_OPEN: 40358330d7bSBrian Somers result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 40458330d7bSBrian Somers descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 4053006ec67SBrian Somers break; 4063006ec67SBrian Somers } 4073006ec67SBrian Somers return result; 4083006ec67SBrian Somers } 4093006ec67SBrian Somers 410ea722969SBrian Somers int 411ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 412ea722969SBrian Somers { 413ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 414ea722969SBrian Somers } 415ea722969SBrian Somers 4163006ec67SBrian Somers static int 417f013f33eSBrian Somers datalink_IsSet(struct fdescriptor *d, const fd_set *fdset) 4183006ec67SBrian Somers { 4193006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4203006ec67SBrian Somers 4213006ec67SBrian Somers switch (dl->state) { 4223006ec67SBrian Somers case DATALINK_CLOSED: 423c7cc5030SBrian Somers case DATALINK_OPENING: 4243006ec67SBrian Somers break; 425c7cc5030SBrian Somers 4263006ec67SBrian Somers case DATALINK_HANGUP: 4273006ec67SBrian Somers case DATALINK_DIAL: 428c116e0c0SBrian Somers case DATALINK_LOGOUT: 4293006ec67SBrian Somers case DATALINK_LOGIN: 4303006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 431c7cc5030SBrian Somers 432c7cc5030SBrian Somers case DATALINK_READY: 433e2ebb036SBrian Somers case DATALINK_LCP: 434e2ebb036SBrian Somers case DATALINK_AUTH: 43592b09558SBrian Somers case DATALINK_CBCP: 4363006ec67SBrian Somers case DATALINK_OPEN: 43758330d7bSBrian Somers return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 43858330d7bSBrian Somers descriptor_IsSet(&dl->physical->desc, fdset); 4393006ec67SBrian Somers } 4403006ec67SBrian Somers return 0; 4413006ec67SBrian Somers } 4423006ec67SBrian Somers 4433006ec67SBrian Somers static void 444f013f33eSBrian Somers datalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 4453006ec67SBrian Somers { 4463006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4473006ec67SBrian Somers 4483006ec67SBrian Somers switch (dl->state) { 4493006ec67SBrian Somers case DATALINK_CLOSED: 450c7cc5030SBrian Somers case DATALINK_OPENING: 4513006ec67SBrian Somers break; 452c7cc5030SBrian Somers 4533006ec67SBrian Somers case DATALINK_HANGUP: 4543006ec67SBrian Somers case DATALINK_DIAL: 455c116e0c0SBrian Somers case DATALINK_LOGOUT: 4563006ec67SBrian Somers case DATALINK_LOGIN: 4573006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 4583006ec67SBrian Somers break; 459c7cc5030SBrian Somers 460c7cc5030SBrian Somers case DATALINK_READY: 461e2ebb036SBrian Somers case DATALINK_LCP: 462e2ebb036SBrian Somers case DATALINK_AUTH: 46392b09558SBrian Somers case DATALINK_CBCP: 4643006ec67SBrian Somers case DATALINK_OPEN: 46558330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 46658330d7bSBrian Somers descriptor_Read(&dl->chap.desc, bundle, fdset); 46758330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 4683006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 4693006ec67SBrian Somers break; 4703006ec67SBrian Somers } 4713006ec67SBrian Somers } 4723006ec67SBrian Somers 4731af29a6eSBrian Somers static int 4749b996792SBrian Somers datalink_Write(struct fdescriptor *d, struct bundle *bundle, 4759b996792SBrian Somers const fd_set *fdset) 4763006ec67SBrian Somers { 4773006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4781af29a6eSBrian Somers int result = 0; 4793006ec67SBrian Somers 4803006ec67SBrian Somers switch (dl->state) { 4813006ec67SBrian Somers case DATALINK_CLOSED: 482c7cc5030SBrian Somers case DATALINK_OPENING: 4833006ec67SBrian Somers break; 484c7cc5030SBrian Somers 4853006ec67SBrian Somers case DATALINK_HANGUP: 4863006ec67SBrian Somers case DATALINK_DIAL: 487c116e0c0SBrian Somers case DATALINK_LOGOUT: 4883006ec67SBrian Somers case DATALINK_LOGIN: 4891af29a6eSBrian Somers result = descriptor_Write(&dl->chat.desc, bundle, fdset); 4903006ec67SBrian Somers break; 491c7cc5030SBrian Somers 492c7cc5030SBrian Somers case DATALINK_READY: 493e2ebb036SBrian Somers case DATALINK_LCP: 494e2ebb036SBrian Somers case DATALINK_AUTH: 49592b09558SBrian Somers case DATALINK_CBCP: 4963006ec67SBrian Somers case DATALINK_OPEN: 49758330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 49858330d7bSBrian Somers result += descriptor_Write(&dl->chap.desc, bundle, fdset); 49958330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 50058330d7bSBrian Somers result += descriptor_Write(&dl->physical->desc, bundle, fdset); 5013006ec67SBrian Somers break; 5023006ec67SBrian Somers } 5031af29a6eSBrian Somers 5041af29a6eSBrian Somers return result; 5053006ec67SBrian Somers } 5063006ec67SBrian Somers 5076d666775SBrian Somers static void 5089c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 509e2ebb036SBrian Somers { 5102fc2f705SBrian Somers int stayonline; 511e2ebb036SBrian Somers 5122fc2f705SBrian Somers if (how == CLOSE_LCP) 5132fc2f705SBrian Somers datalink_DontHangup(dl); 5142fc2f705SBrian Somers else if (how == CLOSE_STAYDOWN) 5152fc2f705SBrian Somers datalink_StayDown(dl); 5162fc2f705SBrian Somers 5172fc2f705SBrian Somers stayonline = dl->stayonline; 5189c81b87dSBrian Somers dl->stayonline = 0; 5192fc2f705SBrian Somers 5202fc2f705SBrian Somers if (dl->state >= DATALINK_READY && stayonline) { 5216815097bSBrian Somers physical_StopDeviceTimer(dl->physical); 5229c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY); 5239c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 5245d9e6103SBrian Somers physical_Offline(dl->physical); 525e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 526c116e0c0SBrian Somers if (dl->state == DATALINK_LOGOUT) { 5279ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 528c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 529c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n"); 530c116e0c0SBrian Somers } else { 531c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_LOGOUT); 532c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 533c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid logout script\n"); 534c116e0c0SBrian Somers } 535e2ebb036SBrian Somers } else 536e2ebb036SBrian Somers datalink_HangupDone(dl); 537e2ebb036SBrian Somers } 538e2ebb036SBrian Somers } 539e2ebb036SBrian Somers 540e2ebb036SBrian Somers static void 5416d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 5426d666775SBrian Somers { 5436d666775SBrian Somers /* The given FSM is about to start up ! */ 5446d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 545a611cad6SBrian Somers 54692e872e7SBrian Somers if (fp->proto == PROTO_LCP) 547e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 548e2ebb036SBrian Somers } 5496d666775SBrian Somers 5506d666775SBrian Somers static void 5516d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 5526d666775SBrian Somers { 5536d666775SBrian Somers /* The given fsm is now up */ 5546d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 5555e315498SBrian Somers struct lcp *lcp = &dl->physical->link.lcp; 5566d666775SBrian Somers 55792e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 558f0cdd9c0SBrian Somers datalink_GotAuthname(dl, ""); 5595e315498SBrian Somers lcp->auth_ineed = lcp->want_auth; 5605e315498SBrian Somers lcp->auth_iwait = lcp->his_auth; 5615e315498SBrian Somers if (lcp->his_auth || lcp->want_auth) { 5625945a079SBrian Somers if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 5635563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 564dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 5655e315498SBrian Somers Auth2Nam(lcp->his_auth, lcp->his_authtype), 5665e315498SBrian Somers Auth2Nam(lcp->want_auth, lcp->want_authtype)); 5675e315498SBrian Somers if (lcp->his_auth == PROTO_PAP) 568f0cdd9c0SBrian Somers auth_StartReq(&dl->pap); 5695e315498SBrian Somers if (lcp->want_auth == PROTO_CHAP) 570f0cdd9c0SBrian Somers auth_StartReq(&dl->chap.auth); 571e2ebb036SBrian Somers } else 572e2ebb036SBrian Somers datalink_AuthOk(dl); 573e2ebb036SBrian Somers } 574e2ebb036SBrian Somers } 575e2ebb036SBrian Somers 57664cfdfc6SBrian Somers static void 57764cfdfc6SBrian Somers datalink_AuthReInit(struct datalink *dl) 57864cfdfc6SBrian Somers { 57964cfdfc6SBrian Somers auth_StopTimer(&dl->pap); 58064cfdfc6SBrian Somers auth_StopTimer(&dl->chap.auth); 58164cfdfc6SBrian Somers chap_ReInit(&dl->chap); 58264cfdfc6SBrian Somers } 58364cfdfc6SBrian Somers 584e2ebb036SBrian Somers void 585f0cdd9c0SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name) 586643f4904SBrian Somers { 587f0cdd9c0SBrian Somers strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 588f0cdd9c0SBrian Somers dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 589643f4904SBrian Somers } 590643f4904SBrian Somers 591643f4904SBrian Somers void 59292b09558SBrian Somers datalink_NCPUp(struct datalink *dl) 593e2ebb036SBrian Somers { 59406337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 5951df0a3b9SBrian Somers 596dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 5971fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 5981fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 5991fa665f5SBrian Somers case MP_LINKSENT: 600ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 6011fa665f5SBrian Somers return; 6021fa665f5SBrian Somers case MP_UP: 6030a1b5c9dSBrian Somers /* First link in the bundle */ 60492b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 605ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 6060a1b5c9dSBrian Somers /* fall through */ 6071fa665f5SBrian Somers case MP_ADDED: 6080a1b5c9dSBrian Somers /* We're in multilink mode ! */ 6091df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 610ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 6111fa665f5SBrian Somers break; 6121fa665f5SBrian Somers case MP_FAILED: 61349052c95SBrian Somers datalink_AuthNotOk(dl); 61449052c95SBrian Somers return; 61549052c95SBrian Somers } 61649052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 617dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 618897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 619ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 620897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 62149052c95SBrian Somers return; 62250abd4c8SBrian Somers } else { 62350abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 624ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 62592b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 62650abd4c8SBrian Somers } 62749052c95SBrian Somers 62806337856SBrian Somers if (ccpok) { 629dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 630dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 63106337856SBrian Somers } 6329ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 6333b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 6343b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 6356d666775SBrian Somers } 636e2ebb036SBrian Somers 637e2ebb036SBrian Somers void 63892b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl) 63992b09558SBrian Somers { 64092b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 64164cfdfc6SBrian Somers datalink_AuthReInit(dl); 64292b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 64392b09558SBrian Somers } 64492b09558SBrian Somers 64592b09558SBrian Somers void 64692b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl) 64792b09558SBrian Somers { 64892b09558SBrian Somers cbcp_Down(&dl->cbcp); 64992b09558SBrian Somers datalink_CBCPComplete(dl); 65092b09558SBrian Somers } 65192b09558SBrian Somers 65292b09558SBrian Somers void 65392b09558SBrian Somers datalink_AuthOk(struct datalink *dl) 65492b09558SBrian Somers { 6555165af6fSBrian Somers if ((dl->physical->link.lcp.his_callback.opmask & 65692b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) || 6575165af6fSBrian Somers dl->physical->link.lcp.want_callback.opmask & 6585165af6fSBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) && 6595165af6fSBrian Somers !(dl->physical->link.lcp.want_callback.opmask & 6605165af6fSBrian Somers CALLBACK_BIT(CALLBACK_AUTH))) { 6615165af6fSBrian Somers /* We must have agreed CBCP if AUTH isn't there any more */ 66292b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP); 66392b09558SBrian Somers cbcp_Up(&dl->cbcp); 66492b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) { 6655165af6fSBrian Somers /* It's not CBCP */ 66692b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 66792b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 66864cfdfc6SBrian Somers datalink_AuthReInit(dl); 66992b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 67092b09558SBrian Somers } else 67192b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) { 67292b09558SBrian Somers case 0: 67392b09558SBrian Somers datalink_NCPUp(dl); 67492b09558SBrian Somers break; 67592b09558SBrian Somers 67692b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH): 67792b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 67892b09558SBrian Somers sizeof dl->cbcp.fsm.phone); 67992b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 68092b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 68192b09558SBrian Somers dl->peer.authname); 68292b09558SBrian Somers *dl->cbcp.fsm.phone = '\0'; 68392b09558SBrian Somers } else { 68492b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ','); 68592b09558SBrian Somers if (ptr) 68692b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */ 68792b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 68892b09558SBrian Somers dl->cbcp.fsm.phone); 68992b09558SBrian Somers dl->cbcp.required = 1; 69092b09558SBrian Somers } 69192b09558SBrian Somers dl->cbcp.fsm.delay = 0; 69292b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 69364cfdfc6SBrian Somers datalink_AuthReInit(dl); 69492b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 69592b09558SBrian Somers break; 69692b09558SBrian Somers 69792b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164): 69892b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 69992b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1); 70092b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 70192b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 70292b09558SBrian Somers dl->cbcp.fsm.phone); 70392b09558SBrian Somers dl->cbcp.required = 1; 70492b09558SBrian Somers dl->cbcp.fsm.delay = 0; 70592b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 70664cfdfc6SBrian Somers datalink_AuthReInit(dl); 70792b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 70892b09558SBrian Somers break; 70992b09558SBrian Somers 71092b09558SBrian Somers default: 71192b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 71292b09558SBrian Somers dl->name); 71392b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 71464cfdfc6SBrian Somers datalink_AuthReInit(dl); 71592b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 71692b09558SBrian Somers break; 71792b09558SBrian Somers } 71892b09558SBrian Somers } 71992b09558SBrian Somers 72092b09558SBrian Somers void 721e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 722e2ebb036SBrian Somers { 7239ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 72464cfdfc6SBrian Somers datalink_AuthReInit(dl); 725dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 7266d666775SBrian Somers } 7276d666775SBrian Somers 7286d666775SBrian Somers static void 7296d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 7306d666775SBrian Somers { 7316d666775SBrian Somers /* The given FSM has been told to come down */ 7326d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 733a611cad6SBrian Somers 73492e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 735e2ebb036SBrian Somers switch (dl->state) { 736e2ebb036SBrian Somers case DATALINK_OPEN: 737643f4904SBrian Somers peerid_Init(&dl->peer); 73809206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 739ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 740e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 74192b09558SBrian Somers /* fall through (just in case) */ 74292b09558SBrian Somers 74392b09558SBrian Somers case DATALINK_CBCP: 74492b09558SBrian Somers if (!dl->cbcp.required) 74592b09558SBrian Somers cbcp_Down(&dl->cbcp); 74692b09558SBrian Somers /* fall through (just in case) */ 747e2ebb036SBrian Somers 748e2ebb036SBrian Somers case DATALINK_AUTH: 749dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 750dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 7516d666775SBrian Somers } 7529ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 75364cfdfc6SBrian Somers datalink_AuthReInit(dl); 754e2ebb036SBrian Somers } 7556d666775SBrian Somers } 7566d666775SBrian Somers 7576d666775SBrian Somers static void 7586d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 7596d666775SBrian Somers { 7606d666775SBrian Somers /* The given fsm is now down */ 7616d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 7626d666775SBrian Somers 76392e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 76409206a6fSBrian Somers fsm2initial(fp); 7656d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 7669c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 7670a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 7680a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 7696d666775SBrian Somers } 7706d666775SBrian Somers 7713006ec67SBrian Somers struct datalink * 7726f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 7733006ec67SBrian Somers { 7743006ec67SBrian Somers struct datalink *dl; 7753006ec67SBrian Somers 7763006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 7773006ec67SBrian Somers if (dl == NULL) 7783006ec67SBrian Somers return dl; 7793006ec67SBrian Somers 7803006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 7813006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 7823006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 7833006ec67SBrian Somers dl->desc.Read = datalink_Read; 7843006ec67SBrian Somers dl->desc.Write = datalink_Write; 7855b8b8060SBrian Somers 786e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 787e718d1d7SBrian Somers 78873a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 78973a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 790c116e0c0SBrian Somers *dl->cfg.script.logout = '\0'; 79173a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 792f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 793f9545805SBrian Somers *dl->phone.list = '\0'; 794f9545805SBrian Somers dl->phone.next = NULL; 795f9545805SBrian Somers dl->phone.alt = NULL; 796f9545805SBrian Somers dl->phone.chosen = "N/A"; 7979c81b87dSBrian Somers dl->stayonline = 0; 798c7cc5030SBrian Somers dl->script.run = 1; 799c7cc5030SBrian Somers dl->script.packetmode = 1; 8003b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 8015b8b8060SBrian Somers 8023006ec67SBrian Somers dl->bundle = bundle; 8033006ec67SBrian Somers dl->next = NULL; 804e718d1d7SBrian Somers 805c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 806e718d1d7SBrian Somers 807c11e57a3SBrian Somers dl->dial.tries = 0; 808565e35e5SBrian Somers dl->cfg.dial.max = 1; 809565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 810565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 811c11e57a3SBrian Somers dl->cfg.dial.inc = 0; 812c11e57a3SBrian Somers dl->cfg.dial.maxinc = 10; 813e718d1d7SBrian Somers 814abff9baeSBrian Somers dl->reconnect_tries = 0; 815565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 816565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 817abff9baeSBrian Somers 81892b09558SBrian Somers dl->cfg.callback.opmask = 0; 81992b09558SBrian Somers dl->cfg.cbcp.delay = 0; 82092b09558SBrian Somers *dl->cfg.cbcp.phone = '\0'; 82192b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 82292b09558SBrian Somers 8233006ec67SBrian Somers dl->name = strdup(name); 824643f4904SBrian Somers peerid_Init(&dl->peer); 8256f384573SBrian Somers dl->parent = &bundle->fsm; 8263b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 8273b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 8283b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 8293b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 8303b0f8d2eSBrian Somers dl->fsmp.object = dl; 8313b0f8d2eSBrian Somers 8325d9e6103SBrian Somers if ((dl->physical = physical_Create(dl, type)) == NULL) { 8333006ec67SBrian Somers free(dl->name); 8343006ec67SBrian Somers free(dl); 8353006ec67SBrian Somers return NULL; 8363006ec67SBrian Somers } 837f0cdd9c0SBrian Somers 838f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 839f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 84092b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 841c116e0c0SBrian Somers 842c116e0c0SBrian Somers memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 843ffcfaec7SBrian Somers chat_Init(&dl->chat, dl->physical); 8443006ec67SBrian Somers 8459ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 8469ae58882SBrian Somers dl->name, datalink_State(dl)); 8473006ec67SBrian Somers 8483006ec67SBrian Somers return dl; 8493006ec67SBrian Somers } 8503006ec67SBrian Somers 8513006ec67SBrian Somers struct datalink * 852cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 853cd7bd93aSBrian Somers { 854cd7bd93aSBrian Somers struct datalink *dl; 855cd7bd93aSBrian Somers 856cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 857cd7bd93aSBrian Somers if (dl == NULL) 858cd7bd93aSBrian Somers return dl; 859cd7bd93aSBrian Somers 860cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 861cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 862cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 863cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 864cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 865cd7bd93aSBrian Somers 866cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 867cd7bd93aSBrian Somers 868cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 869cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 870cd7bd93aSBrian Somers *dl->phone.list = '\0'; 871643f4904SBrian Somers dl->phone.next = NULL; 872643f4904SBrian Somers dl->phone.alt = NULL; 873643f4904SBrian Somers dl->phone.chosen = "N/A"; 874cd7bd93aSBrian Somers dl->bundle = odl->bundle; 875cd7bd93aSBrian Somers dl->next = NULL; 876c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 877c11e57a3SBrian Somers dl->dial.tries = 0; 878cd7bd93aSBrian Somers dl->reconnect_tries = 0; 879cd7bd93aSBrian Somers dl->name = strdup(name); 880643f4904SBrian Somers peerid_Init(&dl->peer); 881cd7bd93aSBrian Somers dl->parent = odl->parent; 882cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 883643f4904SBrian Somers dl->fsmp.object = dl; 884cd7bd93aSBrian Somers 8855d9e6103SBrian Somers if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { 886cd7bd93aSBrian Somers free(dl->name); 887cd7bd93aSBrian Somers free(dl); 888cd7bd93aSBrian Somers return NULL; 889cd7bd93aSBrian Somers } 890f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 891479508cfSBrian Somers dl->pap.cfg = odl->pap.cfg; 892f0cdd9c0SBrian Somers 893f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 894479508cfSBrian Somers dl->chap.auth.cfg = odl->chap.auth.cfg; 895f0cdd9c0SBrian Somers 896cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 897cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 898cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 899cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 900cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 901cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 902cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 903cd7bd93aSBrian Somers 90492b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 905c116e0c0SBrian Somers 906c116e0c0SBrian Somers memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 907ffcfaec7SBrian Somers chat_Init(&dl->chat, dl->physical); 908cd7bd93aSBrian Somers 9099ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 9109ae58882SBrian Somers dl->name, datalink_State(dl)); 911cd7bd93aSBrian Somers 912cd7bd93aSBrian Somers return dl; 913cd7bd93aSBrian Somers } 914cd7bd93aSBrian Somers 915cd7bd93aSBrian Somers struct datalink * 9163006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 9173006ec67SBrian Somers { 9183006ec67SBrian Somers struct datalink *result; 9193006ec67SBrian Somers 92039d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 921dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 922c7cc5030SBrian Somers datalink_State(dl)); 92339d94652SBrian Somers switch (dl->state) { 92439d94652SBrian Somers case DATALINK_HANGUP: 92539d94652SBrian Somers case DATALINK_DIAL: 92639d94652SBrian Somers case DATALINK_LOGIN: 927ffcfaec7SBrian Somers chat_Finish(&dl->chat); /* Gotta blat the timers ! */ 92839d94652SBrian Somers break; 92939d94652SBrian Somers } 93039d94652SBrian Somers } 9313006ec67SBrian Somers 932ffcfaec7SBrian Somers chat_Destroy(&dl->chat); 933c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 9343006ec67SBrian Somers result = dl->next; 9355d9e6103SBrian Somers physical_Destroy(dl->physical); 9363006ec67SBrian Somers free(dl->name); 9373006ec67SBrian Somers free(dl); 9383006ec67SBrian Somers 9393006ec67SBrian Somers return result; 9403006ec67SBrian Somers } 9413006ec67SBrian Somers 9423006ec67SBrian Somers void 943c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 9443006ec67SBrian Somers { 9456f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 946565e35e5SBrian Somers /* Ignore scripts */ 947565e35e5SBrian Somers runscripts = 0; 948565e35e5SBrian Somers 949c7cc5030SBrian Somers switch (dl->state) { 950c7cc5030SBrian Somers case DATALINK_CLOSED: 9513b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 9523b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 9533b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 9549ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 955565e35e5SBrian Somers dl->reconnect_tries = 9566f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 957c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 958c5a5a6caSBrian Somers dl->script.run = runscripts; 959c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 960c7cc5030SBrian Somers break; 961c7cc5030SBrian Somers 962c7cc5030SBrian Somers case DATALINK_OPENING: 963c7cc5030SBrian Somers if (!dl->script.run && runscripts) 964c7cc5030SBrian Somers dl->script.run = 1; 965c7cc5030SBrian Somers /* fall through */ 966c7cc5030SBrian Somers 967c7cc5030SBrian Somers case DATALINK_DIAL: 968c7cc5030SBrian Somers case DATALINK_LOGIN: 969c7cc5030SBrian Somers case DATALINK_READY: 970c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 971c7cc5030SBrian Somers dl->script.packetmode = 1; 9725e269efeSBrian Somers if (dl->state == DATALINK_READY) { 9735e269efeSBrian Somers dl->script.run = 0; 9745e269efeSBrian Somers datalink_NewState(dl, DATALINK_CARRIER); 9755e269efeSBrian Somers } 976c7cc5030SBrian Somers } 977c7cc5030SBrian Somers break; 9783006ec67SBrian Somers } 9793006ec67SBrian Somers } 9803006ec67SBrian Somers 9813006ec67SBrian Somers void 9829c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 983c7cc5030SBrian Somers { 984c7cc5030SBrian Somers /* Please close */ 985e2ebb036SBrian Somers switch (dl->state) { 986e2ebb036SBrian Somers case DATALINK_OPEN: 987643f4904SBrian Somers peerid_Init(&dl->peer); 98809206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 989e2ebb036SBrian Somers /* fall through */ 990e2ebb036SBrian Somers 99192b09558SBrian Somers case DATALINK_CBCP: 992e2ebb036SBrian Somers case DATALINK_AUTH: 993e2ebb036SBrian Somers case DATALINK_LCP: 99464cfdfc6SBrian Somers datalink_AuthReInit(dl); 9959c81b87dSBrian Somers if (how == CLOSE_LCP) 9962fc2f705SBrian Somers datalink_DontHangup(dl); 9972fc2f705SBrian Somers else if (how == CLOSE_STAYDOWN) 9982fc2f705SBrian Somers datalink_StayDown(dl); 9992fc2f705SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 1000d81ecf9aSBrian Somers break; 1001e2ebb036SBrian Somers 1002e2ebb036SBrian Somers default: 10039c81b87dSBrian Somers datalink_ComeDown(dl, how); 1004c7cc5030SBrian Somers } 1005e2ebb036SBrian Somers } 1006c7cc5030SBrian Somers 1007c7cc5030SBrian Somers void 10089c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 1009c7cc5030SBrian Somers { 1010c7cc5030SBrian Somers /* Carrier is lost */ 1011e2ebb036SBrian Somers switch (dl->state) { 1012e2ebb036SBrian Somers case DATALINK_OPEN: 1013643f4904SBrian Somers peerid_Init(&dl->peer); 101409206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 1015e2ebb036SBrian Somers /* fall through */ 1016e2ebb036SBrian Somers 101792b09558SBrian Somers case DATALINK_CBCP: 1018e2ebb036SBrian Somers case DATALINK_AUTH: 1019e2ebb036SBrian Somers case DATALINK_LCP: 102009206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 1021225e259dSBrian Somers if (dl->state == DATALINK_OPENING) 1022225e259dSBrian Somers return; /* we're doing a callback... */ 1023e2ebb036SBrian Somers /* fall through */ 1024c7cc5030SBrian Somers 1025e2ebb036SBrian Somers default: 10269c81b87dSBrian Somers datalink_ComeDown(dl, how); 1027c7cc5030SBrian Somers } 1028e2ebb036SBrian Somers } 1029c7cc5030SBrian Somers 1030c7cc5030SBrian Somers void 10313006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 10323006ec67SBrian Somers { 10332fc2f705SBrian Somers dl->dial.tries = -1; 10343006ec67SBrian Somers dl->reconnect_tries = 0; 10352fc2f705SBrian Somers dl->stayonline = 0; 10363006ec67SBrian Somers } 1037c7cc5030SBrian Somers 10389c81b87dSBrian Somers void 10399c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 10409c81b87dSBrian Somers { 10412fc2f705SBrian Somers dl->dial.tries = -1; 10422fc2f705SBrian Somers dl->reconnect_tries = 0; 10432fc2f705SBrian Somers dl->stayonline = dl->state >= DATALINK_LCP ? 1 : 0; 10449c81b87dSBrian Somers } 10459c81b87dSBrian Somers 1046643f4904SBrian Somers int 1047643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 1048c7cc5030SBrian Somers { 1049643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 1050643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 1051643f4904SBrian Somers datalink_State(arg->cx)); 1052643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 1053643f4904SBrian Somers if (*arg->cx->peer.authname) 1054643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 1055643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 1056643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 1057565e35e5SBrian Somers else 1058643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 1059643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 1060643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 1061643f4904SBrian Somers arg->cx->peer.enddisc.address, 1062643f4904SBrian Somers arg->cx->peer.enddisc.len)); 1063643f4904SBrian Somers 1064643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 1065643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 1066643f4904SBrian Somers arg->cx->cfg.phone.list); 1067643f4904SBrian Somers if (arg->cx->cfg.dial.max) 1068643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 1069643f4904SBrian Somers arg->cx->cfg.dial.max); 1070565e35e5SBrian Somers else 1071643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 1072b5c347a3SBrian Somers if (arg->cx->cfg.dial.next_timeout >= 0) 1073643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 1074565e35e5SBrian Somers else 1075643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 1076b5c347a3SBrian Somers if (arg->cx->cfg.dial.timeout >= 0) 1077643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 1078565e35e5SBrian Somers else 1079643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 1080643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 1081643f4904SBrian Somers arg->cx->cfg.reconnect.max); 1082643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 1083643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 1084643f4904SBrian Somers else 1085643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 108692b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 108792b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 108892b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 108992b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 109092b09558SBrian Somers else { 109192b09558SBrian Somers int comma = 0; 109292b09558SBrian Somers 109392b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 109492b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 109592b09558SBrian Somers comma = 1; 109692b09558SBrian Somers } 109792b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 109892b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 109992b09558SBrian Somers comma = 1; 110092b09558SBrian Somers } 110192b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 110292b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 110392b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 110492b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 110592b09558SBrian Somers comma = 1; 110692b09558SBrian Somers } 110792b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 110892b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 110992b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 111092b09558SBrian Somers arg->cx->cfg.cbcp.delay); 1111cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: "); 1112cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 1113cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT) 1114cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n"); 1115cf784a89SBrian Somers else 1116cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n"); 1117cf784a89SBrian Somers } else 1118cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 111992b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 112092b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 112192b09558SBrian Somers } else 112292b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 112392b09558SBrian Somers } 112492b09558SBrian Somers 1125643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 1126643f4904SBrian Somers arg->cx->cfg.script.dial); 1127643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 1128643f4904SBrian Somers arg->cx->cfg.script.login); 1129c116e0c0SBrian Somers prompt_Printf(arg->prompt, " Logout Script: %s\n", 1130c116e0c0SBrian Somers arg->cx->cfg.script.logout); 1131643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1132643f4904SBrian Somers arg->cx->cfg.script.hangup); 1133643f4904SBrian Somers return 0; 1134565e35e5SBrian Somers } 1135565e35e5SBrian Somers 1136565e35e5SBrian Somers int 1137565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1138565e35e5SBrian Somers { 113925092092SBrian Somers if (arg->argc == arg->argn+2) { 114025092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 114125092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1142565e35e5SBrian Somers return 0; 1143565e35e5SBrian Somers } 1144565e35e5SBrian Somers return -1; 1145565e35e5SBrian Somers } 1146565e35e5SBrian Somers 1147565e35e5SBrian Somers int 1148565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1149565e35e5SBrian Somers { 1150c11e57a3SBrian Somers const char *sep, *osep; 1151c11e57a3SBrian Somers int timeout, inc, maxinc, tries; 1152565e35e5SBrian Somers 115325092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 115425092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 115525092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1156565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1157565e35e5SBrian Somers randinit(); 1158565e35e5SBrian Somers } else { 115925092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1160565e35e5SBrian Somers 1161565e35e5SBrian Somers if (timeout >= 0) 1162565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1163565e35e5SBrian Somers else { 1164dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1165565e35e5SBrian Somers return -1; 1166565e35e5SBrian Somers } 1167565e35e5SBrian Somers } 1168565e35e5SBrian Somers 1169c11e57a3SBrian Somers sep = strchr(arg->argv[arg->argn], '+'); 1170c11e57a3SBrian Somers if (sep) { 1171c11e57a3SBrian Somers inc = atoi(++sep); 1172c11e57a3SBrian Somers osep = sep; 1173c11e57a3SBrian Somers if (inc >= 0) 1174c11e57a3SBrian Somers arg->cx->cfg.dial.inc = inc; 1175c11e57a3SBrian Somers else { 1176c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid timeout increment\n"); 1177c11e57a3SBrian Somers return -1; 1178c11e57a3SBrian Somers } 1179c11e57a3SBrian Somers sep = strchr(sep, '-'); 1180c11e57a3SBrian Somers if (sep) { 1181c11e57a3SBrian Somers maxinc = atoi(++sep); 1182c11e57a3SBrian Somers if (maxinc >= 0) 1183c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = maxinc; 1184c11e57a3SBrian Somers else { 1185c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 1186c11e57a3SBrian Somers return -1; 1187c11e57a3SBrian Somers } 1188c11e57a3SBrian Somers } else { 1189c11e57a3SBrian Somers /* Default timeout increment */ 1190c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1191c11e57a3SBrian Somers sep = osep; 1192c11e57a3SBrian Somers } 1193c11e57a3SBrian Somers } else { 1194c11e57a3SBrian Somers /* Default timeout increment & max increment */ 1195c11e57a3SBrian Somers arg->cx->cfg.dial.inc = 0; 1196c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1197c11e57a3SBrian Somers sep = arg->argv[arg->argn]; 1198c11e57a3SBrian Somers } 1199c11e57a3SBrian Somers 1200c11e57a3SBrian Somers sep = strchr(sep, '.'); 1201c11e57a3SBrian Somers if (sep) { 1202c11e57a3SBrian Somers if (strcasecmp(++sep, "random") == 0) { 1203565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1204565e35e5SBrian Somers randinit(); 1205565e35e5SBrian Somers } else { 1206c11e57a3SBrian Somers timeout = atoi(sep); 1207565e35e5SBrian Somers if (timeout >= 0) 1208565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1209565e35e5SBrian Somers else { 1210dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1211565e35e5SBrian Somers return -1; 1212565e35e5SBrian Somers } 1213565e35e5SBrian Somers } 1214565e35e5SBrian Somers } else 1215565e35e5SBrian Somers /* Default next timeout */ 1216565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1217565e35e5SBrian Somers 121825092092SBrian Somers if (arg->argc == arg->argn+2) { 121925092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1220565e35e5SBrian Somers 1221565e35e5SBrian Somers if (tries >= 0) { 1222565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1223565e35e5SBrian Somers } else { 1224dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1225565e35e5SBrian Somers return 1; 1226565e35e5SBrian Somers } 1227565e35e5SBrian Somers } 1228565e35e5SBrian Somers return 0; 1229565e35e5SBrian Somers } 1230c11e57a3SBrian Somers 1231565e35e5SBrian Somers return -1; 1232c7cc5030SBrian Somers } 1233c7cc5030SBrian Somers 1234182c898aSBrian Somers static const char * const states[] = { 1235565e35e5SBrian Somers "closed", 1236565e35e5SBrian Somers "opening", 1237565e35e5SBrian Somers "hangup", 1238565e35e5SBrian Somers "dial", 1239eb6e5e05SBrian Somers "carrier", 1240c116e0c0SBrian Somers "logout", 1241565e35e5SBrian Somers "login", 1242565e35e5SBrian Somers "ready", 1243565e35e5SBrian Somers "lcp", 1244565e35e5SBrian Somers "auth", 124592b09558SBrian Somers "cbcp", 1246565e35e5SBrian Somers "open" 1247c7cc5030SBrian Somers }; 1248c7cc5030SBrian Somers 1249643f4904SBrian Somers const char * 1250c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1251c7cc5030SBrian Somers { 1252c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1253c7cc5030SBrian Somers return "unknown"; 1254c7cc5030SBrian Somers return states[dl->state]; 1255c7cc5030SBrian Somers } 12566f384573SBrian Somers 12579ae58882SBrian Somers static void 12589ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 12599ae58882SBrian Somers { 12609ae58882SBrian Somers if (state != dl->state) { 12619ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 12629ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 12639ae58882SBrian Somers states[state]); 12649ae58882SBrian Somers dl->state = state; 12659ae58882SBrian Somers } else 12669ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 12679ae58882SBrian Somers } 12689ae58882SBrian Somers } 12699ae58882SBrian Somers 12706f384573SBrian Somers struct datalink * 127196c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 127287c3786eSBrian Somers int fd, int *auxfd, int *nauxfd) 12736f384573SBrian Somers { 1274b7c5748eSBrian Somers struct datalink *dl, *cdl; 1275479508cfSBrian Somers struct fsm_retry copy; 1276b7c5748eSBrian Somers char *oname; 12776f384573SBrian Somers 127896c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 127996c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 12806f384573SBrian Somers 128196c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 128296c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 128396c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 128496c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 12856f384573SBrian Somers } 1286b7c5748eSBrian Somers 1287b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1288b7c5748eSBrian Somers oname = NULL; 1289b7c5748eSBrian Somers do { 1290b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1291b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1292b7c5748eSBrian Somers if (oname) 1293b7c5748eSBrian Somers free(datalink_NextName(dl)); 1294b7c5748eSBrian Somers else 1295b7c5748eSBrian Somers oname = datalink_NextName(dl); 1296b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1297b7c5748eSBrian Somers } 1298b7c5748eSBrian Somers } while (cdl); 1299b7c5748eSBrian Somers 1300b7c5748eSBrian Somers if (oname) { 1301b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1302b7c5748eSBrian Somers free(oname); 1303b7c5748eSBrian Somers } else { 130496c9bb21SBrian Somers dl->name = strdup(dl->name); 1305b7c5748eSBrian Somers free(iov[*niov].iov_base); 1306b7c5748eSBrian Somers } 1307b7c5748eSBrian Somers (*niov)++; 13086f384573SBrian Somers 13096f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 13106f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 13116f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 13126f384573SBrian Somers dl->desc.Read = datalink_Read; 13136f384573SBrian Somers dl->desc.Write = datalink_Write; 13146f384573SBrian Somers 13156f384573SBrian Somers mp_linkInit(&dl->mp); 13166f384573SBrian Somers *dl->phone.list = '\0'; 13176f384573SBrian Somers dl->phone.next = NULL; 13186f384573SBrian Somers dl->phone.alt = NULL; 13196f384573SBrian Somers dl->phone.chosen = "N/A"; 13206f384573SBrian Somers 13216f384573SBrian Somers dl->bundle = bundle; 13226f384573SBrian Somers dl->next = NULL; 1323c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 1324c11e57a3SBrian Somers dl->dial.tries = 0; 13256f384573SBrian Somers dl->reconnect_tries = 0; 13266f384573SBrian Somers dl->parent = &bundle->fsm; 13276f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 13286f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 13296f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 13306f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 13316f384573SBrian Somers dl->fsmp.object = dl; 13326f384573SBrian Somers 133387c3786eSBrian Somers dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); 133496c9bb21SBrian Somers 133596c9bb21SBrian Somers if (!dl->physical) { 13366f384573SBrian Somers free(dl->name); 13376f384573SBrian Somers free(dl); 13386f384573SBrian Somers dl = NULL; 13399ae58882SBrian Somers } else { 1340479508cfSBrian Somers copy = dl->pap.cfg.fsm; 1341f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 1342479508cfSBrian Somers dl->pap.cfg.fsm = copy; 1343f0cdd9c0SBrian Somers 1344479508cfSBrian Somers copy = dl->chap.auth.cfg.fsm; 1345f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 1346479508cfSBrian Somers dl->chap.auth.cfg.fsm = copy; 1347f0cdd9c0SBrian Somers 134892b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 1349c116e0c0SBrian Somers 1350c116e0c0SBrian Somers memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 1351ffcfaec7SBrian Somers chat_Init(&dl->chat, dl->physical); 13526f384573SBrian Somers 13539ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 13549ae58882SBrian Somers dl->name, datalink_State(dl)); 13559ae58882SBrian Somers } 13569ae58882SBrian Somers 13576f384573SBrian Somers return dl; 13586f384573SBrian Somers } 13596f384573SBrian Somers 13606f384573SBrian Somers int 136185fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 13622cb305afSBrian Somers int *auxfd, int *nauxfd) 13636f384573SBrian Somers { 136496c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 136596c9bb21SBrian Somers int link_fd; 13666f384573SBrian Somers 136796c9bb21SBrian Somers if (dl) { 1368c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 136992b09558SBrian Somers /* The following is purely for the sake of paranoia */ 137092b09558SBrian Somers cbcp_Down(&dl->cbcp); 1371dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1372dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 13736f384573SBrian Somers } 13746f384573SBrian Somers 137596c9bb21SBrian Somers if (*niov >= maxiov - 1) { 137696c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 137796c9bb21SBrian Somers if (dl) { 13786f384573SBrian Somers free(dl->name); 13796f384573SBrian Somers free(dl); 138096c9bb21SBrian Somers } 138196c9bb21SBrian Somers return -1; 138296c9bb21SBrian Somers } 138396c9bb21SBrian Somers 13842cb305afSBrian Somers iov[*niov].iov_base = (void *)dl; 138596c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 13862cb305afSBrian Somers iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL; 138796c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 138896c9bb21SBrian Somers 138987c3786eSBrian Somers link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, 13902cb305afSBrian Somers nauxfd); 139196c9bb21SBrian Somers 139296c9bb21SBrian Somers if (link_fd == -1 && dl) { 139396c9bb21SBrian Somers free(dl->name); 139496c9bb21SBrian Somers free(dl); 139596c9bb21SBrian Somers } 13966f384573SBrian Somers 13976f384573SBrian Somers return link_fd; 13986f384573SBrian Somers } 13996f384573SBrian Somers 140058d55334SBrian Somers void 140158d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 140258d55334SBrian Somers { 140358d55334SBrian Somers free(dl->name); 140458d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 140558d55334SBrian Somers } 140658d55334SBrian Somers 140784917b87SBrian Somers char * 140884917b87SBrian Somers datalink_NextName(struct datalink *dl) 14096f384573SBrian Somers { 14106f384573SBrian Somers int f, n; 141184917b87SBrian Somers char *name, *oname; 14126f384573SBrian Somers 14136f384573SBrian Somers n = strlen(dl->name); 14146f384573SBrian Somers name = (char *)malloc(n+3); 14156f384573SBrian Somers for (f = n - 1; f >= 0; f--) 14166f384573SBrian Somers if (!isdigit(dl->name[f])) 14176f384573SBrian Somers break; 14186f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 14196f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 142084917b87SBrian Somers oname = dl->name; 142154cd8e13SBrian Somers dl->name = name; 142254cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 142384917b87SBrian Somers return oname; 14246f384573SBrian Somers } 1425dd0645c5SBrian Somers 1426dd0645c5SBrian Somers int 1427dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1428dd0645c5SBrian Somers { 1429dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1430dd0645c5SBrian Somers return 0; 1431dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1432dd0645c5SBrian Somers dl->script.run = 0; 1433dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1434dd0645c5SBrian Somers dl->reconnect_tries = 0; 1435f6a4e748SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) && 1436f6a4e748SBrian Somers dl->state <= DATALINK_READY) 1437dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1438dd0645c5SBrian Somers return 1; 1439dd0645c5SBrian Somers } 1440c11e57a3SBrian Somers 1441c11e57a3SBrian Somers int 1442c11e57a3SBrian Somers datalink_GetDialTimeout(struct datalink *dl) 1443c11e57a3SBrian Somers { 1444c11e57a3SBrian Somers int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 1445c11e57a3SBrian Somers 1446c11e57a3SBrian Somers if (dl->dial.incs < dl->cfg.dial.maxinc) 1447c11e57a3SBrian Somers dl->dial.incs++; 1448c11e57a3SBrian Somers 1449c11e57a3SBrian Somers return result; 1450c11e57a3SBrian Somers } 1451