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 "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) 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) { 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 123ffcfaec7SBrian Somers chat_Finish(&dl->chat); 1245d9e6103SBrian Somers physical_Close(dl->physical); 125565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1263006ec67SBrian Somers 12792b09558SBrian Somers if (dl->cbcp.required) { 12892b09558SBrian Somers log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 12992b09558SBrian Somers dl->cfg.callback.opmask = 0; 13092b09558SBrian Somers strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 13192b09558SBrian Somers sizeof dl->cfg.phone.list - 1); 13292b09558SBrian Somers dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 13392b09558SBrian Somers dl->phone.alt = dl->phone.next = NULL; 13492b09558SBrian Somers dl->reconnect_tries = dl->cfg.reconnect.max; 135c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 136c11e57a3SBrian Somers dl->dial.incs = 0; 13792b09558SBrian Somers dl->script.run = 1; 13892b09558SBrian Somers dl->script.packetmode = 1; 13992b09558SBrian Somers if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 14092b09558SBrian Somers log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 14192b09558SBrian Somers bundle_LinksRemoved(dl->bundle); 142c11e57a3SBrian Somers /* if dial.timeout is < 0 (random), we don't override fsm.delay */ 14392b09558SBrian Somers if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 14492b09558SBrian Somers dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 14592b09558SBrian Somers datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 14692b09558SBrian Somers cbcp_Down(&dl->cbcp); 14792b09558SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1481b02dfb4SBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 1491b02dfb4SBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 1500ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 15192b09558SBrian Somers } else if (dl->bundle->CleaningUp || 1526f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 153c11e57a3SBrian Somers ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15481358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 1559ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 156c11e57a3SBrian Somers dl->dial.tries = -1; 157c11e57a3SBrian Somers dl->dial.incs = 0; 1583006ec67SBrian Somers dl->reconnect_tries = 0; 1593006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1604b567bf2SBrian Somers if (!dl->bundle->CleaningUp && 1614b567bf2SBrian Somers !(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND))) 162c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1633006ec67SBrian Somers } else { 1649ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1651b02dfb4SBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 1661b02dfb4SBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 1670ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 168c11e57a3SBrian Somers if (dl->dial.tries < 0) { 169565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 170c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 171c11e57a3SBrian Somers dl->dial.incs = 0; 172abff9baeSBrian Somers dl->reconnect_tries--; 173b42135deSBrian Somers log_Printf(LogCHAT, "%s: Reconnect try %d of %d\n", 174b42135deSBrian Somers dl->name, dl->cfg.reconnect.max - dl->reconnect_tries, 175b42135deSBrian Somers dl->cfg.reconnect.max); 176b42135deSBrian Somers bundle_Notify(dl->bundle, EX_RECONNECT); 177abff9baeSBrian Somers } else { 178f9545805SBrian Somers if (dl->phone.next == NULL) 179c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1803006ec67SBrian Somers else 181565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 182b42135deSBrian Somers bundle_Notify(dl->bundle, EX_REDIAL); 1833006ec67SBrian Somers } 184abff9baeSBrian Somers } 185abff9baeSBrian Somers } 1863006ec67SBrian Somers 187eb6e5e05SBrian Somers const char * 188f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 189f9545805SBrian Somers { 190f9545805SBrian Somers char *phone; 191f9545805SBrian Somers 192f9545805SBrian Somers if (dl->phone.alt == NULL) { 193f9545805SBrian Somers if (dl->phone.next == NULL) { 194f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 195f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 19608da4867SBrian Somers if (*dl->phone.list == '\0') 19708da4867SBrian Somers return ""; 198f9545805SBrian Somers dl->phone.next = dl->phone.list; 199f9545805SBrian Somers } 200f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 201f9545805SBrian Somers } 202f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 203f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 204f9545805SBrian Somers if (*phone) 205b42135deSBrian Somers log_Printf(LogCHAT, "Phone: %s\n", phone); 206f9545805SBrian Somers return phone; 207f9545805SBrian Somers } 208f9545805SBrian Somers 209c5a5a6caSBrian Somers static void 210c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 211c5a5a6caSBrian Somers { 212ffcfaec7SBrian Somers chat_Finish(&dl->chat); 213c116e0c0SBrian Somers 214d345321bSBrian Somers if (!dl->script.packetmode) { 215c11e57a3SBrian Somers dl->dial.tries = -1; 216c11e57a3SBrian Somers dl->dial.incs = 0; 2179ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 2185d9e6103SBrian Somers } else if (!physical_Raw(dl->physical)) { 219c11e57a3SBrian Somers dl->dial.tries = 0; 220dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 221c5a5a6caSBrian Somers if (dl->script.run) { 222c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_LOGOUT); 223c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 224c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid logout script\n"); 225030e4ebbSBrian Somers } else { 2266815097bSBrian Somers physical_StopDeviceTimer(dl->physical); 227030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 228030e4ebbSBrian Somers /* force a redial timeout */ 2295d9e6103SBrian Somers physical_Close(dl->physical); 230c5a5a6caSBrian Somers datalink_HangupDone(dl); 231030e4ebbSBrian Somers } 232c5a5a6caSBrian Somers } else { 233c11e57a3SBrian Somers dl->dial.tries = -1; 234c11e57a3SBrian Somers dl->dial.incs = 0; 235c7cc5030SBrian Somers 236643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 2373b0f8d2eSBrian Somers async_Init(&dl->physical->async); 2383b0f8d2eSBrian Somers 239cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 240cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 2413b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 242503a7782SBrian Somers 2439ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 244dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 245dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm); 246c5a5a6caSBrian Somers } 247c5a5a6caSBrian Somers } 248c5a5a6caSBrian Somers 2493006ec67SBrian Somers static int 250f013f33eSBrian Somers datalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, 2513006ec67SBrian Somers int *n) 2523006ec67SBrian Somers { 2533006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2543006ec67SBrian Somers int result; 2553006ec67SBrian Somers 256310c3babSBrian Somers result = 0; 2573006ec67SBrian Somers switch (dl->state) { 2583006ec67SBrian Somers case DATALINK_CLOSED: 259f6a4e748SBrian Somers if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND| 260f6a4e748SBrian Somers PHYS_FOREGROUND|PHYS_DDIAL)) && 261194c225dSBrian Somers !dl->bundle->CleaningUp) 262565e35e5SBrian Somers /* 26381358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 264f6a4e748SBrian Somers * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter 265f6a4e748SBrian Somers * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up() 266f6a4e748SBrian Somers * and fall through. 267565e35e5SBrian Somers */ 268565e35e5SBrian Somers datalink_Up(dl, 1, 1); 269565e35e5SBrian Somers else 270310c3babSBrian Somers break; 271565e35e5SBrian Somers /* fall through */ 2723006ec67SBrian Somers 2733006ec67SBrian Somers case DATALINK_OPENING: 274c11e57a3SBrian Somers if (dl->dial.timer.state != TIMER_RUNNING) { 275c11e57a3SBrian Somers if (--dl->dial.tries < 0) 276c11e57a3SBrian Somers dl->dial.tries = 0; 2775d9e6103SBrian Somers if (physical_Open(dl->physical, dl->bundle) >= 0) { 278bf1d3ff6SBrian Somers log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 279bf1d3ff6SBrian Somers "Type `~?' for help\r\n", dl->name, 280bf1d3ff6SBrian Somers dl->physical->name.full); 281c5a5a6caSBrian Somers if (dl->script.run) { 2829ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 283c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.dial, 284c39aa54eSBrian Somers *dl->cfg.script.dial ? 285c39aa54eSBrian Somers datalink_ChoosePhoneNumber(dl) : "")) 286c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid dial script\n"); 28781358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 288565e35e5SBrian Somers dl->cfg.dial.max) 289dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 290c11e57a3SBrian Somers dl->name, dl->cfg.dial.max - dl->dial.tries, 291565e35e5SBrian Somers dl->cfg.dial.max); 292c5a5a6caSBrian Somers } else 29314e34a55SBrian Somers datalink_NewState(dl, DATALINK_CARRIER); 2948b09cf1cSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2953006ec67SBrian Somers } else { 29681358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 297565e35e5SBrian Somers dl->cfg.dial.max) 2985d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 299c11e57a3SBrian Somers dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 3003006ec67SBrian Somers else 3015d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device\n"); 3023006ec67SBrian Somers 3033b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 30481358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 305c11e57a3SBrian Somers dl->cfg.dial.max && dl->dial.tries == 0)) { 3069ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 3073006ec67SBrian Somers dl->reconnect_tries = 0; 308c11e57a3SBrian Somers dl->dial.tries = -1; 309bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s\n", 310bf1d3ff6SBrian Somers dl->physical->name.full); 3115b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 312c5a5a6caSBrian Somers } 313bf1d3ff6SBrian Somers if (!dl->bundle->CleaningUp) { 314c11e57a3SBrian Somers int timeout; 315c11e57a3SBrian Somers 316c11e57a3SBrian Somers timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 317b42135deSBrian Somers bundle_Notify(dl->bundle, EX_REDIAL); 318bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 319b5c347a3SBrian Somers dl->physical->name.full, timeout); 3203006ec67SBrian Somers } 3213006ec67SBrian Somers } 322bf1d3ff6SBrian Somers } 323310c3babSBrian Somers break; 3243006ec67SBrian Somers 325eb6e5e05SBrian Somers case DATALINK_CARRIER: 326eb6e5e05SBrian Somers /* Wait for carrier on the device */ 327eb6e5e05SBrian Somers switch (physical_AwaitCarrier(dl->physical)) { 328eb6e5e05SBrian Somers case CARRIER_PENDING: 329eb6e5e05SBrian Somers log_Printf(LogDEBUG, "Waiting for carrier\n"); 330eb6e5e05SBrian Somers return 0; /* A device timer is running to wake us up again */ 331eb6e5e05SBrian Somers 332eb6e5e05SBrian Somers case CARRIER_OK: 33314e34a55SBrian Somers if (dl->script.run) { 334eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 335c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL)) 336c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid login script\n"); 33714e34a55SBrian Somers } else 33814e34a55SBrian Somers datalink_LoginDone(dl); 339eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 340eb6e5e05SBrian Somers 341eb6e5e05SBrian Somers case CARRIER_LOST: 342eb6e5e05SBrian Somers physical_Offline(dl->physical); /* Is this required ? */ 34314e34a55SBrian Somers if (dl->script.run) { 34414e34a55SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 345c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 346c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n"); 347eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 348da8b7034SBrian Somers } else { 349da8b7034SBrian Somers datalink_HangupDone(dl); 350da8b7034SBrian Somers return 0; /* Maybe bundle_CleanDatalinks() has something to do */ 351da8b7034SBrian Somers } 352eb6e5e05SBrian Somers } 353eb6e5e05SBrian Somers 3543006ec67SBrian Somers case DATALINK_HANGUP: 3553006ec67SBrian Somers case DATALINK_DIAL: 356c116e0c0SBrian Somers case DATALINK_LOGOUT: 3573006ec67SBrian Somers case DATALINK_LOGIN: 3583006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 3593006ec67SBrian Somers switch (dl->chat.state) { 3603006ec67SBrian Somers case CHAT_DONE: 3613006ec67SBrian Somers /* script succeeded */ 3623006ec67SBrian Somers switch(dl->state) { 3633006ec67SBrian Somers case DATALINK_HANGUP: 3643006ec67SBrian Somers datalink_HangupDone(dl); 3653006ec67SBrian Somers break; 3663006ec67SBrian Somers case DATALINK_DIAL: 367eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_CARRIER); 3681342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 369c116e0c0SBrian Somers case DATALINK_LOGOUT: 370c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 371c116e0c0SBrian Somers physical_Offline(dl->physical); 372c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 373c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n"); 374c116e0c0SBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3753006ec67SBrian Somers case DATALINK_LOGIN: 37647dd77c1SBrian Somers dl->phone.alt = NULL; 377c5a5a6caSBrian Somers datalink_LoginDone(dl); 378b51a60ccSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3793006ec67SBrian Somers } 3803006ec67SBrian Somers break; 3813006ec67SBrian Somers case CHAT_FAILED: 3823006ec67SBrian Somers /* Going down - script failed */ 383dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 3843006ec67SBrian Somers switch(dl->state) { 3853006ec67SBrian Somers case DATALINK_HANGUP: 3863006ec67SBrian Somers datalink_HangupDone(dl); 3873006ec67SBrian Somers break; 3883006ec67SBrian Somers case DATALINK_DIAL: 389c116e0c0SBrian Somers case DATALINK_LOGOUT: 3903006ec67SBrian Somers case DATALINK_LOGIN: 3919ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 392c116e0c0SBrian Somers physical_Offline(dl->physical); 393c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 394c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n"); 3951342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3963006ec67SBrian Somers } 3973006ec67SBrian Somers break; 3983006ec67SBrian Somers } 3993006ec67SBrian Somers break; 400c7cc5030SBrian Somers 401c7cc5030SBrian Somers case DATALINK_READY: 402e2ebb036SBrian Somers case DATALINK_LCP: 403e2ebb036SBrian Somers case DATALINK_AUTH: 40492b09558SBrian Somers case DATALINK_CBCP: 4053006ec67SBrian Somers case DATALINK_OPEN: 40658330d7bSBrian Somers result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 40758330d7bSBrian Somers descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 4083006ec67SBrian Somers break; 4093006ec67SBrian Somers } 4103006ec67SBrian Somers return result; 4113006ec67SBrian Somers } 4123006ec67SBrian Somers 413ea722969SBrian Somers int 414ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 415ea722969SBrian Somers { 416ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 417ea722969SBrian Somers } 418ea722969SBrian Somers 4193006ec67SBrian Somers static int 420f013f33eSBrian Somers datalink_IsSet(struct fdescriptor *d, const fd_set *fdset) 4213006ec67SBrian Somers { 4223006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4233006ec67SBrian Somers 4243006ec67SBrian Somers switch (dl->state) { 4253006ec67SBrian Somers case DATALINK_CLOSED: 426c7cc5030SBrian Somers case DATALINK_OPENING: 4273006ec67SBrian Somers break; 428c7cc5030SBrian Somers 4293006ec67SBrian Somers case DATALINK_HANGUP: 4303006ec67SBrian Somers case DATALINK_DIAL: 431c116e0c0SBrian Somers case DATALINK_LOGOUT: 4323006ec67SBrian Somers case DATALINK_LOGIN: 4333006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 434c7cc5030SBrian Somers 435c7cc5030SBrian Somers case DATALINK_READY: 436e2ebb036SBrian Somers case DATALINK_LCP: 437e2ebb036SBrian Somers case DATALINK_AUTH: 43892b09558SBrian Somers case DATALINK_CBCP: 4393006ec67SBrian Somers case DATALINK_OPEN: 44058330d7bSBrian Somers return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 44158330d7bSBrian Somers descriptor_IsSet(&dl->physical->desc, fdset); 4423006ec67SBrian Somers } 4433006ec67SBrian Somers return 0; 4443006ec67SBrian Somers } 4453006ec67SBrian Somers 4463006ec67SBrian Somers static void 447f013f33eSBrian Somers datalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 4483006ec67SBrian Somers { 4493006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4503006ec67SBrian Somers 4513006ec67SBrian Somers switch (dl->state) { 4523006ec67SBrian Somers case DATALINK_CLOSED: 453c7cc5030SBrian Somers case DATALINK_OPENING: 4543006ec67SBrian Somers break; 455c7cc5030SBrian Somers 4563006ec67SBrian Somers case DATALINK_HANGUP: 4573006ec67SBrian Somers case DATALINK_DIAL: 458c116e0c0SBrian Somers case DATALINK_LOGOUT: 4593006ec67SBrian Somers case DATALINK_LOGIN: 4603006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 4613006ec67SBrian Somers break; 462c7cc5030SBrian Somers 463c7cc5030SBrian Somers case DATALINK_READY: 464e2ebb036SBrian Somers case DATALINK_LCP: 465e2ebb036SBrian Somers case DATALINK_AUTH: 46692b09558SBrian Somers case DATALINK_CBCP: 4673006ec67SBrian Somers case DATALINK_OPEN: 46858330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 46958330d7bSBrian Somers descriptor_Read(&dl->chap.desc, bundle, fdset); 47058330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 4713006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 4723006ec67SBrian Somers break; 4733006ec67SBrian Somers } 4743006ec67SBrian Somers } 4753006ec67SBrian Somers 4761af29a6eSBrian Somers static int 477f013f33eSBrian Somers datalink_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 4783006ec67SBrian Somers { 4793006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4801af29a6eSBrian Somers int result = 0; 4813006ec67SBrian Somers 4823006ec67SBrian Somers switch (dl->state) { 4833006ec67SBrian Somers case DATALINK_CLOSED: 484c7cc5030SBrian Somers case DATALINK_OPENING: 4853006ec67SBrian Somers break; 486c7cc5030SBrian Somers 4873006ec67SBrian Somers case DATALINK_HANGUP: 4883006ec67SBrian Somers case DATALINK_DIAL: 489c116e0c0SBrian Somers case DATALINK_LOGOUT: 4903006ec67SBrian Somers case DATALINK_LOGIN: 4911af29a6eSBrian Somers result = descriptor_Write(&dl->chat.desc, bundle, fdset); 4923006ec67SBrian Somers break; 493c7cc5030SBrian Somers 494c7cc5030SBrian Somers case DATALINK_READY: 495e2ebb036SBrian Somers case DATALINK_LCP: 496e2ebb036SBrian Somers case DATALINK_AUTH: 49792b09558SBrian Somers case DATALINK_CBCP: 4983006ec67SBrian Somers case DATALINK_OPEN: 49958330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 50058330d7bSBrian Somers result += descriptor_Write(&dl->chap.desc, bundle, fdset); 50158330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 50258330d7bSBrian Somers result += descriptor_Write(&dl->physical->desc, bundle, fdset); 5033006ec67SBrian Somers break; 5043006ec67SBrian Somers } 5051af29a6eSBrian Somers 5061af29a6eSBrian Somers return result; 5073006ec67SBrian Somers } 5083006ec67SBrian Somers 5096d666775SBrian Somers static void 5109c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 511e2ebb036SBrian Somers { 5129c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 513c11e57a3SBrian Somers dl->dial.tries = -1; 514e2ebb036SBrian Somers dl->reconnect_tries = 0; 5157729a182SBrian Somers if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 5169c81b87dSBrian Somers dl->stayonline = 1; 517e2ebb036SBrian Somers } 518e2ebb036SBrian Somers 5197729a182SBrian Somers if (dl->state >= DATALINK_READY && dl->stayonline) { 5209c81b87dSBrian Somers dl->stayonline = 0; 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; 972c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 973c7cc5030SBrian Somers datalink_LoginDone(dl); 974c7cc5030SBrian Somers } 975c7cc5030SBrian Somers break; 9763006ec67SBrian Somers } 9773006ec67SBrian Somers } 9783006ec67SBrian Somers 9793006ec67SBrian Somers void 9809c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 981c7cc5030SBrian Somers { 982c7cc5030SBrian Somers /* Please close */ 983e2ebb036SBrian Somers switch (dl->state) { 984e2ebb036SBrian Somers case DATALINK_OPEN: 985643f4904SBrian Somers peerid_Init(&dl->peer); 98609206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 987e2ebb036SBrian Somers /* fall through */ 988e2ebb036SBrian Somers 98992b09558SBrian Somers case DATALINK_CBCP: 990e2ebb036SBrian Somers case DATALINK_AUTH: 991e2ebb036SBrian Somers case DATALINK_LCP: 99264cfdfc6SBrian Somers datalink_AuthReInit(dl); 993dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 9949c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 995c11e57a3SBrian Somers dl->dial.tries = -1; 996c7cc5030SBrian Somers dl->reconnect_tries = 0; 9979c81b87dSBrian Somers if (how == CLOSE_LCP) 9989c81b87dSBrian Somers dl->stayonline = 1; 999c7cc5030SBrian Somers } 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 { 10333006ec67SBrian Somers dl->reconnect_tries = 0; 10343006ec67SBrian Somers } 1035c7cc5030SBrian Somers 10369c81b87dSBrian Somers void 10379c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 10389c81b87dSBrian Somers { 10397729a182SBrian Somers if (dl->state >= DATALINK_LCP) 10409c81b87dSBrian Somers dl->stayonline = 1; 10419c81b87dSBrian Somers } 10429c81b87dSBrian Somers 1043643f4904SBrian Somers int 1044643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 1045c7cc5030SBrian Somers { 1046643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 1047643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 1048643f4904SBrian Somers datalink_State(arg->cx)); 1049643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 1050643f4904SBrian Somers if (*arg->cx->peer.authname) 1051643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 1052643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 1053643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 1054565e35e5SBrian Somers else 1055643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 1056643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 1057643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 1058643f4904SBrian Somers arg->cx->peer.enddisc.address, 1059643f4904SBrian Somers arg->cx->peer.enddisc.len)); 1060643f4904SBrian Somers 1061643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 1062643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 1063643f4904SBrian Somers arg->cx->cfg.phone.list); 1064643f4904SBrian Somers if (arg->cx->cfg.dial.max) 1065643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 1066643f4904SBrian Somers arg->cx->cfg.dial.max); 1067565e35e5SBrian Somers else 1068643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 1069b5c347a3SBrian Somers if (arg->cx->cfg.dial.next_timeout >= 0) 1070643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 1071565e35e5SBrian Somers else 1072643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 1073b5c347a3SBrian Somers if (arg->cx->cfg.dial.timeout >= 0) 1074643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 1075565e35e5SBrian Somers else 1076643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 1077643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 1078643f4904SBrian Somers arg->cx->cfg.reconnect.max); 1079643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 1080643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 1081643f4904SBrian Somers else 1082643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 108392b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 108492b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 108592b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 108692b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 108792b09558SBrian Somers else { 108892b09558SBrian Somers int comma = 0; 108992b09558SBrian Somers 109092b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 109192b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 109292b09558SBrian Somers comma = 1; 109392b09558SBrian Somers } 109492b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 109592b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 109692b09558SBrian Somers comma = 1; 109792b09558SBrian Somers } 109892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 109992b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 110092b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 110192b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 110292b09558SBrian Somers comma = 1; 110392b09558SBrian Somers } 110492b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 110592b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 110692b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 110792b09558SBrian Somers arg->cx->cfg.cbcp.delay); 1108cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: "); 1109cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 1110cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT) 1111cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n"); 1112cf784a89SBrian Somers else 1113cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n"); 1114cf784a89SBrian Somers } else 1115cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 111692b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 111792b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 111892b09558SBrian Somers } else 111992b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 112092b09558SBrian Somers } 112192b09558SBrian Somers 1122643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 1123643f4904SBrian Somers arg->cx->cfg.script.dial); 1124643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 1125643f4904SBrian Somers arg->cx->cfg.script.login); 1126c116e0c0SBrian Somers prompt_Printf(arg->prompt, " Logout Script: %s\n", 1127c116e0c0SBrian Somers arg->cx->cfg.script.logout); 1128643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1129643f4904SBrian Somers arg->cx->cfg.script.hangup); 1130643f4904SBrian Somers return 0; 1131565e35e5SBrian Somers } 1132565e35e5SBrian Somers 1133565e35e5SBrian Somers int 1134565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1135565e35e5SBrian Somers { 113625092092SBrian Somers if (arg->argc == arg->argn+2) { 113725092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 113825092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1139565e35e5SBrian Somers return 0; 1140565e35e5SBrian Somers } 1141565e35e5SBrian Somers return -1; 1142565e35e5SBrian Somers } 1143565e35e5SBrian Somers 1144565e35e5SBrian Somers int 1145565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1146565e35e5SBrian Somers { 1147c11e57a3SBrian Somers const char *sep, *osep; 1148c11e57a3SBrian Somers int timeout, inc, maxinc, tries; 1149565e35e5SBrian Somers 115025092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 115125092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 115225092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1153565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1154565e35e5SBrian Somers randinit(); 1155565e35e5SBrian Somers } else { 115625092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1157565e35e5SBrian Somers 1158565e35e5SBrian Somers if (timeout >= 0) 1159565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1160565e35e5SBrian Somers else { 1161dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1162565e35e5SBrian Somers return -1; 1163565e35e5SBrian Somers } 1164565e35e5SBrian Somers } 1165565e35e5SBrian Somers 1166c11e57a3SBrian Somers sep = strchr(arg->argv[arg->argn], '+'); 1167c11e57a3SBrian Somers if (sep) { 1168c11e57a3SBrian Somers inc = atoi(++sep); 1169c11e57a3SBrian Somers osep = sep; 1170c11e57a3SBrian Somers if (inc >= 0) 1171c11e57a3SBrian Somers arg->cx->cfg.dial.inc = inc; 1172c11e57a3SBrian Somers else { 1173c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid timeout increment\n"); 1174c11e57a3SBrian Somers return -1; 1175c11e57a3SBrian Somers } 1176c11e57a3SBrian Somers sep = strchr(sep, '-'); 1177c11e57a3SBrian Somers if (sep) { 1178c11e57a3SBrian Somers maxinc = atoi(++sep); 1179c11e57a3SBrian Somers if (maxinc >= 0) 1180c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = maxinc; 1181c11e57a3SBrian Somers else { 1182c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 1183c11e57a3SBrian Somers return -1; 1184c11e57a3SBrian Somers } 1185c11e57a3SBrian Somers } else { 1186c11e57a3SBrian Somers /* Default timeout increment */ 1187c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1188c11e57a3SBrian Somers sep = osep; 1189c11e57a3SBrian Somers } 1190c11e57a3SBrian Somers } else { 1191c11e57a3SBrian Somers /* Default timeout increment & max increment */ 1192c11e57a3SBrian Somers arg->cx->cfg.dial.inc = 0; 1193c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1194c11e57a3SBrian Somers sep = arg->argv[arg->argn]; 1195c11e57a3SBrian Somers } 1196c11e57a3SBrian Somers 1197c11e57a3SBrian Somers sep = strchr(sep, '.'); 1198c11e57a3SBrian Somers if (sep) { 1199c11e57a3SBrian Somers if (strcasecmp(++sep, "random") == 0) { 1200565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1201565e35e5SBrian Somers randinit(); 1202565e35e5SBrian Somers } else { 1203c11e57a3SBrian Somers timeout = atoi(sep); 1204565e35e5SBrian Somers if (timeout >= 0) 1205565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1206565e35e5SBrian Somers else { 1207dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1208565e35e5SBrian Somers return -1; 1209565e35e5SBrian Somers } 1210565e35e5SBrian Somers } 1211565e35e5SBrian Somers } else 1212565e35e5SBrian Somers /* Default next timeout */ 1213565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1214565e35e5SBrian Somers 121525092092SBrian Somers if (arg->argc == arg->argn+2) { 121625092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1217565e35e5SBrian Somers 1218565e35e5SBrian Somers if (tries >= 0) { 1219565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1220565e35e5SBrian Somers } else { 1221dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1222565e35e5SBrian Somers return 1; 1223565e35e5SBrian Somers } 1224565e35e5SBrian Somers } 1225565e35e5SBrian Somers return 0; 1226565e35e5SBrian Somers } 1227c11e57a3SBrian Somers 1228565e35e5SBrian Somers return -1; 1229c7cc5030SBrian Somers } 1230c7cc5030SBrian Somers 1231182c898aSBrian Somers static const char * const states[] = { 1232565e35e5SBrian Somers "closed", 1233565e35e5SBrian Somers "opening", 1234565e35e5SBrian Somers "hangup", 1235565e35e5SBrian Somers "dial", 1236eb6e5e05SBrian Somers "carrier", 1237c116e0c0SBrian Somers "logout", 1238565e35e5SBrian Somers "login", 1239565e35e5SBrian Somers "ready", 1240565e35e5SBrian Somers "lcp", 1241565e35e5SBrian Somers "auth", 124292b09558SBrian Somers "cbcp", 1243565e35e5SBrian Somers "open" 1244c7cc5030SBrian Somers }; 1245c7cc5030SBrian Somers 1246643f4904SBrian Somers const char * 1247c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1248c7cc5030SBrian Somers { 1249c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1250c7cc5030SBrian Somers return "unknown"; 1251c7cc5030SBrian Somers return states[dl->state]; 1252c7cc5030SBrian Somers } 12536f384573SBrian Somers 12549ae58882SBrian Somers static void 12559ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 12569ae58882SBrian Somers { 12579ae58882SBrian Somers if (state != dl->state) { 12589ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 12599ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 12609ae58882SBrian Somers states[state]); 12619ae58882SBrian Somers dl->state = state; 12629ae58882SBrian Somers } else 12639ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 12649ae58882SBrian Somers } 12659ae58882SBrian Somers } 12669ae58882SBrian Somers 12676f384573SBrian Somers struct datalink * 126896c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 126987c3786eSBrian Somers int fd, int *auxfd, int *nauxfd) 12706f384573SBrian Somers { 1271b7c5748eSBrian Somers struct datalink *dl, *cdl; 1272479508cfSBrian Somers struct fsm_retry copy; 1273b7c5748eSBrian Somers char *oname; 12746f384573SBrian Somers 127596c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 127696c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 12776f384573SBrian Somers 127896c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 127996c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 128096c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 128196c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 12826f384573SBrian Somers } 1283b7c5748eSBrian Somers 1284b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1285b7c5748eSBrian Somers oname = NULL; 1286b7c5748eSBrian Somers do { 1287b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1288b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1289b7c5748eSBrian Somers if (oname) 1290b7c5748eSBrian Somers free(datalink_NextName(dl)); 1291b7c5748eSBrian Somers else 1292b7c5748eSBrian Somers oname = datalink_NextName(dl); 1293b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1294b7c5748eSBrian Somers } 1295b7c5748eSBrian Somers } while (cdl); 1296b7c5748eSBrian Somers 1297b7c5748eSBrian Somers if (oname) { 1298b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1299b7c5748eSBrian Somers free(oname); 1300b7c5748eSBrian Somers } else { 130196c9bb21SBrian Somers dl->name = strdup(dl->name); 1302b7c5748eSBrian Somers free(iov[*niov].iov_base); 1303b7c5748eSBrian Somers } 1304b7c5748eSBrian Somers (*niov)++; 13056f384573SBrian Somers 13066f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 13076f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 13086f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 13096f384573SBrian Somers dl->desc.Read = datalink_Read; 13106f384573SBrian Somers dl->desc.Write = datalink_Write; 13116f384573SBrian Somers 13126f384573SBrian Somers mp_linkInit(&dl->mp); 13136f384573SBrian Somers *dl->phone.list = '\0'; 13146f384573SBrian Somers dl->phone.next = NULL; 13156f384573SBrian Somers dl->phone.alt = NULL; 13166f384573SBrian Somers dl->phone.chosen = "N/A"; 13176f384573SBrian Somers 13186f384573SBrian Somers dl->bundle = bundle; 13196f384573SBrian Somers dl->next = NULL; 1320c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 1321c11e57a3SBrian Somers dl->dial.tries = 0; 13226f384573SBrian Somers dl->reconnect_tries = 0; 13236f384573SBrian Somers dl->parent = &bundle->fsm; 13246f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 13256f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 13266f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 13276f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 13286f384573SBrian Somers dl->fsmp.object = dl; 13296f384573SBrian Somers 133087c3786eSBrian Somers dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); 133196c9bb21SBrian Somers 133296c9bb21SBrian Somers if (!dl->physical) { 13336f384573SBrian Somers free(dl->name); 13346f384573SBrian Somers free(dl); 13356f384573SBrian Somers dl = NULL; 13369ae58882SBrian Somers } else { 1337479508cfSBrian Somers copy = dl->pap.cfg.fsm; 1338f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 1339479508cfSBrian Somers dl->pap.cfg.fsm = copy; 1340f0cdd9c0SBrian Somers 1341479508cfSBrian Somers copy = dl->chap.auth.cfg.fsm; 1342f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 1343479508cfSBrian Somers dl->chap.auth.cfg.fsm = copy; 1344f0cdd9c0SBrian Somers 134592b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 1346c116e0c0SBrian Somers 1347c116e0c0SBrian Somers memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 1348ffcfaec7SBrian Somers chat_Init(&dl->chat, dl->physical); 13496f384573SBrian Somers 13509ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 13519ae58882SBrian Somers dl->name, datalink_State(dl)); 13529ae58882SBrian Somers } 13539ae58882SBrian Somers 13546f384573SBrian Somers return dl; 13556f384573SBrian Somers } 13566f384573SBrian Somers 13576f384573SBrian Somers int 135885fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 13592cb305afSBrian Somers int *auxfd, int *nauxfd) 13606f384573SBrian Somers { 136196c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 136296c9bb21SBrian Somers int link_fd; 13636f384573SBrian Somers 136496c9bb21SBrian Somers if (dl) { 1365c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 136692b09558SBrian Somers /* The following is purely for the sake of paranoia */ 136792b09558SBrian Somers cbcp_Down(&dl->cbcp); 1368dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1369dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 13706f384573SBrian Somers } 13716f384573SBrian Somers 137296c9bb21SBrian Somers if (*niov >= maxiov - 1) { 137396c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 137496c9bb21SBrian Somers if (dl) { 13756f384573SBrian Somers free(dl->name); 13766f384573SBrian Somers free(dl); 137796c9bb21SBrian Somers } 137896c9bb21SBrian Somers return -1; 137996c9bb21SBrian Somers } 138096c9bb21SBrian Somers 13812cb305afSBrian Somers iov[*niov].iov_base = (void *)dl; 138296c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 13832cb305afSBrian Somers iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL; 138496c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 138596c9bb21SBrian Somers 138687c3786eSBrian Somers link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, 13872cb305afSBrian Somers nauxfd); 138896c9bb21SBrian Somers 138996c9bb21SBrian Somers if (link_fd == -1 && dl) { 139096c9bb21SBrian Somers free(dl->name); 139196c9bb21SBrian Somers free(dl); 139296c9bb21SBrian Somers } 13936f384573SBrian Somers 13946f384573SBrian Somers return link_fd; 13956f384573SBrian Somers } 13966f384573SBrian Somers 139758d55334SBrian Somers void 139858d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 139958d55334SBrian Somers { 140058d55334SBrian Somers free(dl->name); 140158d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 140258d55334SBrian Somers } 140358d55334SBrian Somers 140484917b87SBrian Somers char * 140584917b87SBrian Somers datalink_NextName(struct datalink *dl) 14066f384573SBrian Somers { 14076f384573SBrian Somers int f, n; 140884917b87SBrian Somers char *name, *oname; 14096f384573SBrian Somers 14106f384573SBrian Somers n = strlen(dl->name); 14116f384573SBrian Somers name = (char *)malloc(n+3); 14126f384573SBrian Somers for (f = n - 1; f >= 0; f--) 14136f384573SBrian Somers if (!isdigit(dl->name[f])) 14146f384573SBrian Somers break; 14156f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 14166f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 141784917b87SBrian Somers oname = dl->name; 141854cd8e13SBrian Somers dl->name = name; 141954cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 142084917b87SBrian Somers return oname; 14216f384573SBrian Somers } 1422dd0645c5SBrian Somers 1423dd0645c5SBrian Somers int 1424dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1425dd0645c5SBrian Somers { 1426dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1427dd0645c5SBrian Somers return 0; 1428dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1429dd0645c5SBrian Somers dl->script.run = 0; 1430dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1431dd0645c5SBrian Somers dl->reconnect_tries = 0; 1432f6a4e748SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) && 1433f6a4e748SBrian Somers dl->state <= DATALINK_READY) 1434dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1435dd0645c5SBrian Somers return 1; 1436dd0645c5SBrian Somers } 1437c11e57a3SBrian Somers 1438c11e57a3SBrian Somers int 1439c11e57a3SBrian Somers datalink_GetDialTimeout(struct datalink *dl) 1440c11e57a3SBrian Somers { 1441c11e57a3SBrian Somers int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 1442c11e57a3SBrian Somers 1443c11e57a3SBrian Somers if (dl->dial.incs < dl->cfg.dial.maxinc) 1444c11e57a3SBrian Somers dl->dial.incs++; 1445c11e57a3SBrian Somers 1446c11e57a3SBrian Somers return result; 1447c11e57a3SBrian Somers } 1448