136285Sbrian/*- 236285Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 336285Sbrian * All rights reserved. 436285Sbrian * 536285Sbrian * Redistribution and use in source and binary forms, with or without 636285Sbrian * modification, are permitted provided that the following conditions 736285Sbrian * are met: 836285Sbrian * 1. Redistributions of source code must retain the above copyright 936285Sbrian * notice, this list of conditions and the following disclaimer. 1036285Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1136285Sbrian * notice, this list of conditions and the following disclaimer in the 1236285Sbrian * documentation and/or other materials provided with the distribution. 1336285Sbrian * 1436285Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1536285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1636285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1736285Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1836285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1936285Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2036285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2136285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2236285Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2336285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2436285Sbrian * SUCH DAMAGE. 2536285Sbrian * 2650479Speter * $FreeBSD$ 2736285Sbrian */ 2836285Sbrian 2943313Sbrian#include <sys/param.h> 3036285Sbrian#include <netinet/in.h> 3136285Sbrian#include <netinet/in_systm.h> 3236285Sbrian#include <netinet/ip.h> 3381634Sbrian#include <sys/socket.h> 3436285Sbrian#include <sys/un.h> 3536285Sbrian 3636285Sbrian#include <ctype.h> 37102500Sbrian#include <stdarg.h> 3836285Sbrian#include <stdio.h> 3936285Sbrian#include <stdlib.h> 4036285Sbrian#include <string.h> 4136285Sbrian#include <sys/uio.h> 4236285Sbrian#include <termios.h> 4336285Sbrian 4446686Sbrian#include "layer.h" 4536285Sbrian#include "mbuf.h" 4636285Sbrian#include "log.h" 4736285Sbrian#include "defs.h" 4836285Sbrian#include "timer.h" 4936285Sbrian#include "fsm.h" 5036285Sbrian#include "descriptor.h" 5136285Sbrian#include "lqr.h" 5236285Sbrian#include "hdlc.h" 5363484Sbrian#include "lcp.h" 5436285Sbrian#include "async.h" 5536285Sbrian#include "throughput.h" 5636285Sbrian#include "ccp.h" 5736285Sbrian#include "link.h" 5836285Sbrian#include "physical.h" 5936285Sbrian#include "iplist.h" 6036285Sbrian#include "slcompress.h" 6181634Sbrian#include "ncpaddr.h" 6236285Sbrian#include "ipcp.h" 6336285Sbrian#include "filter.h" 6436285Sbrian#include "mp.h" 6543313Sbrian#ifndef NORADIUS 6643313Sbrian#include "radius.h" 6743313Sbrian#endif 6881634Sbrian#include "ipv6cp.h" 6981634Sbrian#include "ncp.h" 7036285Sbrian#include "bundle.h" 7136285Sbrian#include "chat.h" 7236285Sbrian#include "auth.h" 7336285Sbrian#include "prompt.h" 7446686Sbrian#include "proto.h" 7536285Sbrian#include "pap.h" 7636285Sbrian#include "chap.h" 7736285Sbrian#include "command.h" 7838174Sbrian#include "cbcp.h" 7936285Sbrian#include "datalink.h" 8036285Sbrian 8136285Sbrianstatic void datalink_LoginDone(struct datalink *); 82134789Sbrianstatic void datalink_NewState(struct datalink *, unsigned); 83136375Sbrianstatic char *datalink_NextName(struct datalink *); 8436285Sbrian 8536285Sbrianstatic void 8636285Sbriandatalink_OpenTimeout(void *v) 8736285Sbrian{ 8836285Sbrian struct datalink *dl = (struct datalink *)v; 8936285Sbrian 9044468Sbrian timer_Stop(&dl->dial.timer); 9136285Sbrian if (dl->state == DATALINK_OPENING) 9259084Sbrian log_Printf(LogCHAT, "%s: Redial timer expired.\n", dl->name); 9336285Sbrian} 9436285Sbrian 9544261Sbrianstatic int 9636285Sbriandatalink_StartDialTimer(struct datalink *dl, int Timeout) 9736285Sbrian{ 9844261Sbrian int result = Timeout; 9944261Sbrian 10044468Sbrian timer_Stop(&dl->dial.timer); 10185362Sbrian if (Timeout < 0) 10285362Sbrian result = (random() % DIAL_TIMEOUT) + 1; 10385362Sbrian dl->dial.timer.load = result ? result * SECTICKS : 1; 10485362Sbrian dl->dial.timer.func = datalink_OpenTimeout; 10585362Sbrian dl->dial.timer.name = "dial"; 10685362Sbrian dl->dial.timer.arg = dl; 10785362Sbrian timer_Start(&dl->dial.timer); 10885362Sbrian if (dl->state == DATALINK_OPENING) 10985362Sbrian log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 11085362Sbrian dl->name, result); 11144261Sbrian return result; 11236285Sbrian} 11336285Sbrian 11436285Sbrianstatic void 11536285Sbriandatalink_HangupDone(struct datalink *dl) 11636285Sbrian{ 11736285Sbrian if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 11846686Sbrian dl->physical->fd != -1) { 11946686Sbrian /* Don't close our device if the link is dedicated */ 12036285Sbrian datalink_LoginDone(dl); 12136285Sbrian return; 12236285Sbrian } 12336285Sbrian 12454055Sbrian chat_Finish(&dl->chat); 12546686Sbrian physical_Close(dl->physical); 12636285Sbrian dl->phone.chosen = "N/A"; 12736285Sbrian 12838174Sbrian if (dl->cbcp.required) { 12938174Sbrian log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 13038174Sbrian dl->cfg.callback.opmask = 0; 13138174Sbrian strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 13238174Sbrian sizeof dl->cfg.phone.list - 1); 13338174Sbrian dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 13438174Sbrian dl->phone.alt = dl->phone.next = NULL; 13538174Sbrian dl->reconnect_tries = dl->cfg.reconnect.max; 13644468Sbrian dl->dial.tries = dl->cfg.dial.max; 13744468Sbrian dl->dial.incs = 0; 13838174Sbrian dl->script.run = 1; 13938174Sbrian dl->script.packetmode = 1; 14038174Sbrian if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 14138174Sbrian log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 14238174Sbrian bundle_LinksRemoved(dl->bundle); 14344468Sbrian /* if dial.timeout is < 0 (random), we don't override fsm.delay */ 14438174Sbrian if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 14538174Sbrian dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 14638174Sbrian datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 14738174Sbrian cbcp_Down(&dl->cbcp); 14838174Sbrian datalink_NewState(dl, DATALINK_OPENING); 14952412Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 15052412Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 15145385Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 15238174Sbrian } else if (dl->bundle->CleaningUp || 15336285Sbrian (dl->physical->type == PHYS_DIRECT) || 15444468Sbrian ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15536465Sbrian !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 15636285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 15744468Sbrian dl->dial.tries = -1; 15844468Sbrian dl->dial.incs = 0; 15936285Sbrian dl->reconnect_tries = 0; 16036285Sbrian bundle_LinkClosed(dl->bundle, dl); 16158455Sbrian if (!dl->bundle->CleaningUp && 16258455Sbrian !(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND))) 16344468Sbrian datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 16436285Sbrian } else { 16536285Sbrian datalink_NewState(dl, DATALINK_OPENING); 16652412Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 16752412Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 16845385Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 16944468Sbrian if (dl->dial.tries < 0) { 17036285Sbrian datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 17144468Sbrian dl->dial.tries = dl->cfg.dial.max; 17244468Sbrian dl->dial.incs = 0; 17336285Sbrian dl->reconnect_tries--; 17459084Sbrian log_Printf(LogCHAT, "%s: Reconnect try %d of %d\n", 17559084Sbrian dl->name, dl->cfg.reconnect.max - dl->reconnect_tries, 17659084Sbrian dl->cfg.reconnect.max); 17759084Sbrian bundle_Notify(dl->bundle, EX_RECONNECT); 17836285Sbrian } else { 17936285Sbrian if (dl->phone.next == NULL) 18044468Sbrian datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 18136285Sbrian else 18236285Sbrian datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 18359084Sbrian bundle_Notify(dl->bundle, EX_REDIAL); 18436285Sbrian } 18536285Sbrian } 18636285Sbrian} 18736285Sbrian 18849472Sbrianconst char * 18936285Sbriandatalink_ChoosePhoneNumber(struct datalink *dl) 19036285Sbrian{ 19136285Sbrian char *phone; 19236285Sbrian 19336285Sbrian if (dl->phone.alt == NULL) { 19436285Sbrian if (dl->phone.next == NULL) { 19536285Sbrian strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 19636285Sbrian dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 19748003Sbrian if (*dl->phone.list == '\0') 19848003Sbrian return ""; 19936285Sbrian dl->phone.next = dl->phone.list; 20036285Sbrian } 20136285Sbrian dl->phone.alt = strsep(&dl->phone.next, ":"); 20236285Sbrian } 20336285Sbrian phone = strsep(&dl->phone.alt, "|"); 20436285Sbrian dl->phone.chosen = *phone ? phone : "[NONE]"; 20536285Sbrian if (*phone) 20659084Sbrian log_Printf(LogCHAT, "Phone: %s\n", phone); 20736285Sbrian return phone; 20836285Sbrian} 20936285Sbrian 21036285Sbrianstatic void 21136285Sbriandatalink_LoginDone(struct datalink *dl) 21236285Sbrian{ 21354055Sbrian chat_Finish(&dl->chat); 21452488Sbrian 21598243Sbrian if (!dl->script.packetmode) { 21644468Sbrian dl->dial.tries = -1; 21744468Sbrian dl->dial.incs = 0; 21836285Sbrian datalink_NewState(dl, DATALINK_READY); 21946686Sbrian } else if (!physical_Raw(dl->physical)) { 22044468Sbrian dl->dial.tries = 0; 22136285Sbrian log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 22298243Sbrian if (dl->script.run) { 22352488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 22454914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 22554914Sbrian log_Printf(LogWARN, "Invalid logout script\n"); 22636285Sbrian } else { 22747061Sbrian physical_StopDeviceTimer(dl->physical); 22836285Sbrian if (dl->physical->type == PHYS_DEDICATED) 22936285Sbrian /* force a redial timeout */ 23046686Sbrian physical_Close(dl->physical); 23136285Sbrian datalink_HangupDone(dl); 23236285Sbrian } 23336285Sbrian } else { 23444468Sbrian dl->dial.tries = -1; 23544468Sbrian dl->dial.incs = 0; 23636285Sbrian 23736285Sbrian hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 23891623Sbrian async_Setup(&dl->physical->async); 23936285Sbrian 24036285Sbrian lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 24136285Sbrian 0 : dl->physical->link.lcp.cfg.openmode); 24236285Sbrian ccp_Setup(&dl->physical->link.ccp); 24336285Sbrian 24436285Sbrian datalink_NewState(dl, DATALINK_LCP); 24536285Sbrian fsm_Up(&dl->physical->link.lcp.fsm); 24636285Sbrian fsm_Open(&dl->physical->link.lcp.fsm); 24736285Sbrian } 24836285Sbrian} 24936285Sbrian 25036285Sbrianstatic int 25158028Sbriandatalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, 25236285Sbrian int *n) 25336285Sbrian{ 25436285Sbrian struct datalink *dl = descriptor2datalink(d); 25536285Sbrian int result; 25636285Sbrian 25736285Sbrian result = 0; 25836285Sbrian switch (dl->state) { 25936285Sbrian case DATALINK_CLOSED: 26053830Sbrian if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND| 26153830Sbrian PHYS_FOREGROUND|PHYS_DDIAL)) && 26247863Sbrian !dl->bundle->CleaningUp) 26336285Sbrian /* 26436465Sbrian * Our first time in - DEDICATED & DDIAL never come down, and 26553830Sbrian * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter 26653830Sbrian * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up() 26753830Sbrian * and fall through. 26836285Sbrian */ 26936285Sbrian datalink_Up(dl, 1, 1); 27036285Sbrian else 27136285Sbrian break; 272102413Scharnier /* FALLTHROUGH */ 27336285Sbrian 27436285Sbrian case DATALINK_OPENING: 27544468Sbrian if (dl->dial.timer.state != TIMER_RUNNING) { 27644468Sbrian if (--dl->dial.tries < 0) 27744468Sbrian dl->dial.tries = 0; 278134789Sbrian if (physical_Open(dl->physical) >= 0) { 27938200Sbrian log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 28038200Sbrian "Type `~?' for help\r\n", dl->name, 28138200Sbrian dl->physical->name.full); 28236285Sbrian if (dl->script.run) { 28336285Sbrian datalink_NewState(dl, DATALINK_DIAL); 28454914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.dial, 28554914Sbrian *dl->cfg.script.dial ? 28654914Sbrian datalink_ChoosePhoneNumber(dl) : "")) 28754914Sbrian log_Printf(LogWARN, "Invalid dial script\n"); 28836465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 28936285Sbrian dl->cfg.dial.max) 29036285Sbrian log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 29144468Sbrian dl->name, dl->cfg.dial.max - dl->dial.tries, 29236285Sbrian dl->cfg.dial.max); 29336285Sbrian } else 29451978Sbrian datalink_NewState(dl, DATALINK_CARRIER); 29541830Sbrian return datalink_UpdateSet(d, r, w, e, n); 29636285Sbrian } else { 29736465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 29836285Sbrian dl->cfg.dial.max) 29946686Sbrian log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 30044468Sbrian dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 30136285Sbrian else 30246686Sbrian log_Printf(LogCHAT, "Failed to open device\n"); 30336285Sbrian 30436285Sbrian if (dl->bundle->CleaningUp || 30536465Sbrian (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 30644468Sbrian dl->cfg.dial.max && dl->dial.tries == 0)) { 30736285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 30836285Sbrian dl->reconnect_tries = 0; 30944468Sbrian dl->dial.tries = -1; 31038200Sbrian log_WritePrompts(dl, "Failed to open %s\n", 31138200Sbrian dl->physical->name.full); 31236285Sbrian bundle_LinkClosed(dl->bundle, dl); 31336285Sbrian } 31438200Sbrian if (!dl->bundle->CleaningUp) { 31544468Sbrian int timeout; 31644468Sbrian 31744468Sbrian timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 31859084Sbrian bundle_Notify(dl->bundle, EX_REDIAL); 31938200Sbrian log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 32044261Sbrian dl->physical->name.full, timeout); 32138200Sbrian } 32236285Sbrian } 32336285Sbrian } 32436285Sbrian break; 32536285Sbrian 32649472Sbrian case DATALINK_CARRIER: 32749472Sbrian /* Wait for carrier on the device */ 32849472Sbrian switch (physical_AwaitCarrier(dl->physical)) { 32949472Sbrian case CARRIER_PENDING: 33049472Sbrian log_Printf(LogDEBUG, "Waiting for carrier\n"); 33149472Sbrian return 0; /* A device timer is running to wake us up again */ 33249472Sbrian 33349472Sbrian case CARRIER_OK: 33451978Sbrian if (dl->script.run) { 33551978Sbrian datalink_NewState(dl, DATALINK_LOGIN); 33654914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL)) 33754914Sbrian log_Printf(LogWARN, "Invalid login script\n"); 33851978Sbrian } else 33951978Sbrian datalink_LoginDone(dl); 34049472Sbrian return datalink_UpdateSet(d, r, w, e, n); 34149472Sbrian 34249472Sbrian case CARRIER_LOST: 34349472Sbrian physical_Offline(dl->physical); /* Is this required ? */ 34498243Sbrian if (dl->script.run) { 34551978Sbrian datalink_NewState(dl, DATALINK_HANGUP); 34654914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 34754914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 34853070Sbrian return datalink_UpdateSet(d, r, w, e, n); 34953070Sbrian } else { 35051978Sbrian datalink_HangupDone(dl); 35153070Sbrian return 0; /* Maybe bundle_CleanDatalinks() has something to do */ 35253070Sbrian } 35349472Sbrian } 35449472Sbrian 35536285Sbrian case DATALINK_HANGUP: 35636285Sbrian case DATALINK_DIAL: 35752488Sbrian case DATALINK_LOGOUT: 35836285Sbrian case DATALINK_LOGIN: 35936285Sbrian result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 36036285Sbrian switch (dl->chat.state) { 36136285Sbrian case CHAT_DONE: 36236285Sbrian /* script succeeded */ 36336285Sbrian switch(dl->state) { 36436285Sbrian case DATALINK_HANGUP: 36536285Sbrian datalink_HangupDone(dl); 36636285Sbrian break; 36736285Sbrian case DATALINK_DIAL: 36849472Sbrian datalink_NewState(dl, DATALINK_CARRIER); 36936285Sbrian return datalink_UpdateSet(d, r, w, e, n); 37052488Sbrian case DATALINK_LOGOUT: 37152488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 37252488Sbrian physical_Offline(dl->physical); 37354914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 37454914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 37552488Sbrian return datalink_UpdateSet(d, r, w, e, n); 37636285Sbrian case DATALINK_LOGIN: 37742390Sbrian dl->phone.alt = NULL; 37836285Sbrian datalink_LoginDone(dl); 37942905Sbrian return datalink_UpdateSet(d, r, w, e, n); 38036285Sbrian } 38136285Sbrian break; 38236285Sbrian case CHAT_FAILED: 38336285Sbrian /* Going down - script failed */ 38436285Sbrian log_Printf(LogWARN, "Chat script failed\n"); 38536285Sbrian switch(dl->state) { 38636285Sbrian case DATALINK_HANGUP: 38736285Sbrian datalink_HangupDone(dl); 38836285Sbrian break; 38936285Sbrian case DATALINK_DIAL: 39052488Sbrian case DATALINK_LOGOUT: 39136285Sbrian case DATALINK_LOGIN: 39236285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 39352488Sbrian physical_Offline(dl->physical); 39454914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 39554914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 39636285Sbrian return datalink_UpdateSet(d, r, w, e, n); 39736285Sbrian } 39836285Sbrian break; 39936285Sbrian } 40036285Sbrian break; 40136285Sbrian 40236285Sbrian case DATALINK_READY: 40336285Sbrian case DATALINK_LCP: 40436285Sbrian case DATALINK_AUTH: 40538174Sbrian case DATALINK_CBCP: 40636285Sbrian case DATALINK_OPEN: 40743888Sbrian result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 40843888Sbrian descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 40936285Sbrian break; 41036285Sbrian } 41136285Sbrian return result; 41236285Sbrian} 41336285Sbrian 41436285Sbrianint 41536285Sbriandatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 41636285Sbrian{ 41736285Sbrian return physical_RemoveFromSet(dl->physical, r, w, e); 41836285Sbrian} 41936285Sbrian 42036285Sbrianstatic int 42158028Sbriandatalink_IsSet(struct fdescriptor *d, const fd_set *fdset) 42236285Sbrian{ 42336285Sbrian struct datalink *dl = descriptor2datalink(d); 42436285Sbrian 42536285Sbrian switch (dl->state) { 42636285Sbrian case DATALINK_CLOSED: 42736285Sbrian case DATALINK_OPENING: 42836285Sbrian break; 42936285Sbrian 43036285Sbrian case DATALINK_HANGUP: 43136285Sbrian case DATALINK_DIAL: 43252488Sbrian case DATALINK_LOGOUT: 43336285Sbrian case DATALINK_LOGIN: 43436285Sbrian return descriptor_IsSet(&dl->chat.desc, fdset); 43536285Sbrian 43636285Sbrian case DATALINK_READY: 43736285Sbrian case DATALINK_LCP: 43836285Sbrian case DATALINK_AUTH: 43938174Sbrian case DATALINK_CBCP: 44036285Sbrian case DATALINK_OPEN: 44143888Sbrian return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 44243888Sbrian descriptor_IsSet(&dl->physical->desc, fdset); 44336285Sbrian } 44436285Sbrian return 0; 44536285Sbrian} 44636285Sbrian 44736285Sbrianstatic void 44858028Sbriandatalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 44936285Sbrian{ 45036285Sbrian struct datalink *dl = descriptor2datalink(d); 45136285Sbrian 45236285Sbrian switch (dl->state) { 45336285Sbrian case DATALINK_CLOSED: 45436285Sbrian case DATALINK_OPENING: 45536285Sbrian break; 45636285Sbrian 45736285Sbrian case DATALINK_HANGUP: 45836285Sbrian case DATALINK_DIAL: 45952488Sbrian case DATALINK_LOGOUT: 46036285Sbrian case DATALINK_LOGIN: 46136285Sbrian descriptor_Read(&dl->chat.desc, bundle, fdset); 46236285Sbrian break; 46336285Sbrian 46436285Sbrian case DATALINK_READY: 46536285Sbrian case DATALINK_LCP: 46636285Sbrian case DATALINK_AUTH: 46738174Sbrian case DATALINK_CBCP: 46836285Sbrian case DATALINK_OPEN: 46943888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 47043888Sbrian descriptor_Read(&dl->chap.desc, bundle, fdset); 47143888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 47243888Sbrian descriptor_Read(&dl->physical->desc, bundle, fdset); 47336285Sbrian break; 47436285Sbrian } 47536285Sbrian} 47636285Sbrian 47737141Sbrianstatic int 47867912Sbriandatalink_Write(struct fdescriptor *d, struct bundle *bundle, 47967912Sbrian const fd_set *fdset) 48036285Sbrian{ 48136285Sbrian struct datalink *dl = descriptor2datalink(d); 48237141Sbrian int result = 0; 48336285Sbrian 48436285Sbrian switch (dl->state) { 48536285Sbrian case DATALINK_CLOSED: 48636285Sbrian case DATALINK_OPENING: 48736285Sbrian break; 48836285Sbrian 48936285Sbrian case DATALINK_HANGUP: 49036285Sbrian case DATALINK_DIAL: 49152488Sbrian case DATALINK_LOGOUT: 49236285Sbrian case DATALINK_LOGIN: 49393418Sbrian if ((result = descriptor_Write(&dl->chat.desc, bundle, fdset)) == -1) { 49493418Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 49593418Sbrian result = 0; 49693418Sbrian } 49736285Sbrian break; 49836285Sbrian 49936285Sbrian case DATALINK_READY: 50036285Sbrian case DATALINK_LCP: 50136285Sbrian case DATALINK_AUTH: 50238174Sbrian case DATALINK_CBCP: 50336285Sbrian case DATALINK_OPEN: 50443888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 50593418Sbrian switch (descriptor_Write(&dl->chap.desc, bundle, fdset)) { 50693418Sbrian case -1: 50793418Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 50893418Sbrian break; 50993418Sbrian case 1: 51093418Sbrian result++; 51193418Sbrian } 51243888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 51393418Sbrian switch (descriptor_Write(&dl->physical->desc, bundle, fdset)) { 51493418Sbrian case -1: 51593418Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 51693418Sbrian break; 51793418Sbrian case 1: 51893418Sbrian result++; 51993418Sbrian } 52036285Sbrian break; 52136285Sbrian } 52237141Sbrian 52337141Sbrian return result; 52436285Sbrian} 52536285Sbrian 52693418Sbrianvoid 52737007Sbriandatalink_ComeDown(struct datalink *dl, int how) 52836285Sbrian{ 52971970Sbrian int stayonline; 53036285Sbrian 53171970Sbrian if (how == CLOSE_LCP) 53271970Sbrian datalink_DontHangup(dl); 53371970Sbrian else if (how == CLOSE_STAYDOWN) 53471970Sbrian datalink_StayDown(dl); 53571970Sbrian 53671970Sbrian stayonline = dl->stayonline; 53771970Sbrian dl->stayonline = 0; 53871970Sbrian 53971970Sbrian if (dl->state >= DATALINK_READY && stayonline) { 54047061Sbrian physical_StopDeviceTimer(dl->physical); 54137007Sbrian datalink_NewState(dl, DATALINK_READY); 54237007Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 54346686Sbrian physical_Offline(dl->physical); 54436285Sbrian if (dl->script.run && dl->state != DATALINK_OPENING) { 54552488Sbrian if (dl->state == DATALINK_LOGOUT) { 54652488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 54754914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 54854914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 54952488Sbrian } else { 55052488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 55154914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 55254914Sbrian log_Printf(LogWARN, "Invalid logout script\n"); 55352488Sbrian } 55436285Sbrian } else 55536285Sbrian datalink_HangupDone(dl); 55636285Sbrian } 55736285Sbrian} 55836285Sbrian 55936285Sbrianstatic void 56036285Sbriandatalink_LayerStart(void *v, struct fsm *fp) 56136285Sbrian{ 56236285Sbrian /* The given FSM is about to start up ! */ 56336285Sbrian struct datalink *dl = (struct datalink *)v; 56436285Sbrian 56536285Sbrian if (fp->proto == PROTO_LCP) 56636285Sbrian (*dl->parent->LayerStart)(dl->parent->object, fp); 56736285Sbrian} 56836285Sbrian 56936285Sbrianstatic void 57036285Sbriandatalink_LayerUp(void *v, struct fsm *fp) 57136285Sbrian{ 57236285Sbrian /* The given fsm is now up */ 57336285Sbrian struct datalink *dl = (struct datalink *)v; 57444106Sbrian struct lcp *lcp = &dl->physical->link.lcp; 57536285Sbrian 57636285Sbrian if (fp->proto == PROTO_LCP) { 57743693Sbrian datalink_GotAuthname(dl, ""); 57844106Sbrian lcp->auth_ineed = lcp->want_auth; 57944106Sbrian lcp->auth_iwait = lcp->his_auth; 58044106Sbrian if (lcp->his_auth || lcp->want_auth) { 58145350Sbrian if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 58236285Sbrian bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 58336285Sbrian log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 58444106Sbrian Auth2Nam(lcp->his_auth, lcp->his_authtype), 58544106Sbrian Auth2Nam(lcp->want_auth, lcp->want_authtype)); 58644106Sbrian if (lcp->his_auth == PROTO_PAP) 58743693Sbrian auth_StartReq(&dl->pap); 58844106Sbrian if (lcp->want_auth == PROTO_CHAP) 58943693Sbrian auth_StartReq(&dl->chap.auth); 59036285Sbrian } else 59136285Sbrian datalink_AuthOk(dl); 59279165Sbrian } else if (fp->proto == PROTO_CCP) 59379165Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.ccp.fsm); 59436285Sbrian} 59536285Sbrian 59644094Sbrianstatic void 59744094Sbriandatalink_AuthReInit(struct datalink *dl) 59844094Sbrian{ 59944094Sbrian auth_StopTimer(&dl->pap); 60044094Sbrian auth_StopTimer(&dl->chap.auth); 60144094Sbrian chap_ReInit(&dl->chap); 60244094Sbrian} 60344094Sbrian 60436285Sbrianvoid 60543693Sbriandatalink_GotAuthname(struct datalink *dl, const char *name) 60636285Sbrian{ 60743693Sbrian strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 60843693Sbrian dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 60936285Sbrian} 61036285Sbrian 61136285Sbrianvoid 61238174Sbriandatalink_NCPUp(struct datalink *dl) 61336285Sbrian{ 61437320Sbrian int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 61536310Sbrian 61636285Sbrian if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 61736285Sbrian /* we've authenticated in multilink mode ! */ 61836285Sbrian switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 61936285Sbrian case MP_LINKSENT: 62036285Sbrian /* We've handed the link off to another ppp (well, we will soon) ! */ 62136285Sbrian return; 62236285Sbrian case MP_UP: 62336285Sbrian /* First link in the bundle */ 62438174Sbrian auth_Select(dl->bundle, dl->peer.authname); 62549434Sbrian bundle_CalculateBandwidth(dl->bundle); 626102413Scharnier /* FALLTHROUGH */ 62736285Sbrian case MP_ADDED: 62836285Sbrian /* We're in multilink mode ! */ 62936310Sbrian dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 63049434Sbrian bundle_CalculateBandwidth(dl->bundle); 63136285Sbrian break; 63236285Sbrian case MP_FAILED: 63336285Sbrian datalink_AuthNotOk(dl); 63436285Sbrian return; 63536285Sbrian } 63636285Sbrian } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 63736285Sbrian log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 63837160Sbrian datalink_NewState(dl, DATALINK_OPEN); 63949434Sbrian bundle_CalculateBandwidth(dl->bundle); 64037160Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 64136285Sbrian return; 64236285Sbrian } else { 64336285Sbrian dl->bundle->ncp.mp.peer = dl->peer; 64481634Sbrian ncp_SetLink(&dl->bundle->ncp, &dl->physical->link); 64538174Sbrian auth_Select(dl->bundle, dl->peer.authname); 64636285Sbrian } 64736285Sbrian 64837320Sbrian if (ccpok) { 64937320Sbrian fsm_Up(&dl->physical->link.ccp.fsm); 65037320Sbrian fsm_Open(&dl->physical->link.ccp.fsm); 65137320Sbrian } 65236285Sbrian datalink_NewState(dl, DATALINK_OPEN); 65336285Sbrian bundle_NewPhase(dl->bundle, PHASE_NETWORK); 65436285Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 65536285Sbrian} 65636285Sbrian 65736285Sbrianvoid 65838174Sbriandatalink_CBCPComplete(struct datalink *dl) 65938174Sbrian{ 66038174Sbrian datalink_NewState(dl, DATALINK_LCP); 66144094Sbrian datalink_AuthReInit(dl); 66238174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 66338174Sbrian} 66438174Sbrian 66538174Sbrianvoid 66638174Sbriandatalink_CBCPFailed(struct datalink *dl) 66738174Sbrian{ 66838174Sbrian cbcp_Down(&dl->cbcp); 66938174Sbrian datalink_CBCPComplete(dl); 67038174Sbrian} 67138174Sbrian 67238174Sbrianvoid 67338174Sbriandatalink_AuthOk(struct datalink *dl) 67438174Sbrian{ 67542600Sbrian if ((dl->physical->link.lcp.his_callback.opmask & 67642600Sbrian CALLBACK_BIT(CALLBACK_CBCP) || 67742600Sbrian dl->physical->link.lcp.want_callback.opmask & 67842600Sbrian CALLBACK_BIT(CALLBACK_CBCP)) && 67942600Sbrian !(dl->physical->link.lcp.want_callback.opmask & 68042600Sbrian CALLBACK_BIT(CALLBACK_AUTH))) { 68142600Sbrian /* We must have agreed CBCP if AUTH isn't there any more */ 68238174Sbrian datalink_NewState(dl, DATALINK_CBCP); 68338174Sbrian cbcp_Up(&dl->cbcp); 68438174Sbrian } else if (dl->physical->link.lcp.want_callback.opmask) { 68542600Sbrian /* It's not CBCP */ 68638174Sbrian log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 68738174Sbrian datalink_NewState(dl, DATALINK_LCP); 68844094Sbrian datalink_AuthReInit(dl); 68938174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 69038174Sbrian } else 69138174Sbrian switch (dl->physical->link.lcp.his_callback.opmask) { 69238174Sbrian case 0: 69338174Sbrian datalink_NCPUp(dl); 69438174Sbrian break; 69538174Sbrian 69638174Sbrian case CALLBACK_BIT(CALLBACK_AUTH): 69738174Sbrian auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 69838174Sbrian sizeof dl->cbcp.fsm.phone); 69938174Sbrian if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 70038174Sbrian log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 70138174Sbrian dl->peer.authname); 70238174Sbrian *dl->cbcp.fsm.phone = '\0'; 70338174Sbrian } else { 70438174Sbrian char *ptr = strchr(dl->cbcp.fsm.phone, ','); 70538174Sbrian if (ptr) 70638174Sbrian *ptr = '\0'; /* Call back on the first number */ 70738174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 70838174Sbrian dl->cbcp.fsm.phone); 70938174Sbrian dl->cbcp.required = 1; 71038174Sbrian } 71138174Sbrian dl->cbcp.fsm.delay = 0; 71238174Sbrian datalink_NewState(dl, DATALINK_LCP); 71344094Sbrian datalink_AuthReInit(dl); 71438174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 71538174Sbrian break; 71638174Sbrian 71738174Sbrian case CALLBACK_BIT(CALLBACK_E164): 71838174Sbrian strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 71938174Sbrian sizeof dl->cbcp.fsm.phone - 1); 72038174Sbrian dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 72138174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 72238174Sbrian dl->cbcp.fsm.phone); 72338174Sbrian dl->cbcp.required = 1; 72438174Sbrian dl->cbcp.fsm.delay = 0; 72538174Sbrian datalink_NewState(dl, DATALINK_LCP); 72644094Sbrian datalink_AuthReInit(dl); 72738174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 72838174Sbrian break; 72938174Sbrian 73038174Sbrian default: 73138174Sbrian log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 73238174Sbrian dl->name); 73338174Sbrian datalink_NewState(dl, DATALINK_LCP); 73444094Sbrian datalink_AuthReInit(dl); 73538174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 73638174Sbrian break; 73738174Sbrian } 73838174Sbrian} 73938174Sbrian 74038174Sbrianvoid 74136285Sbriandatalink_AuthNotOk(struct datalink *dl) 74236285Sbrian{ 74336285Sbrian datalink_NewState(dl, DATALINK_LCP); 74444094Sbrian datalink_AuthReInit(dl); 74536285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 74636285Sbrian} 74736285Sbrian 74836285Sbrianstatic void 74936285Sbriandatalink_LayerDown(void *v, struct fsm *fp) 75036285Sbrian{ 75136285Sbrian /* The given FSM has been told to come down */ 75236285Sbrian struct datalink *dl = (struct datalink *)v; 75336285Sbrian 75436285Sbrian if (fp->proto == PROTO_LCP) { 75536285Sbrian switch (dl->state) { 75636285Sbrian case DATALINK_OPEN: 75736285Sbrian peerid_Init(&dl->peer); 75837060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 75936928Sbrian datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 76036285Sbrian (*dl->parent->LayerDown)(dl->parent->object, fp); 761102413Scharnier /* FALLTHROUGH (just in case) */ 76236285Sbrian 76338174Sbrian case DATALINK_CBCP: 76438174Sbrian if (!dl->cbcp.required) 76538174Sbrian cbcp_Down(&dl->cbcp); 766102413Scharnier /* FALLTHROUGH (just in case) */ 76738174Sbrian 76836285Sbrian case DATALINK_AUTH: 76936285Sbrian timer_Stop(&dl->pap.authtimer); 77036285Sbrian timer_Stop(&dl->chap.auth.authtimer); 77136285Sbrian } 77236285Sbrian datalink_NewState(dl, DATALINK_LCP); 77344094Sbrian datalink_AuthReInit(dl); 77436285Sbrian } 77536285Sbrian} 77636285Sbrian 77736285Sbrianstatic void 77836285Sbriandatalink_LayerFinish(void *v, struct fsm *fp) 77936285Sbrian{ 78036285Sbrian /* The given fsm is now down */ 78136285Sbrian struct datalink *dl = (struct datalink *)v; 78236285Sbrian 78336285Sbrian if (fp->proto == PROTO_LCP) { 78437060Sbrian fsm2initial(fp); 78536285Sbrian (*dl->parent->LayerFinish)(dl->parent->object, fp); 78637007Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 78736285Sbrian } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 78836285Sbrian fsm_Open(fp); /* CCP goes to ST_STOPPED */ 78936285Sbrian} 79036285Sbrian 79136285Sbrianstruct datalink * 79236285Sbriandatalink_Create(const char *name, struct bundle *bundle, int type) 79336285Sbrian{ 79436285Sbrian struct datalink *dl; 79536285Sbrian 79636285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 79736285Sbrian if (dl == NULL) 79836285Sbrian return dl; 79936285Sbrian 80036285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 80136285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 80236285Sbrian dl->desc.IsSet = datalink_IsSet; 80336285Sbrian dl->desc.Read = datalink_Read; 80436285Sbrian dl->desc.Write = datalink_Write; 80536285Sbrian 80636285Sbrian dl->state = DATALINK_CLOSED; 80736285Sbrian 80836285Sbrian *dl->cfg.script.dial = '\0'; 80936285Sbrian *dl->cfg.script.login = '\0'; 81052488Sbrian *dl->cfg.script.logout = '\0'; 81136285Sbrian *dl->cfg.script.hangup = '\0'; 81236285Sbrian *dl->cfg.phone.list = '\0'; 81336285Sbrian *dl->phone.list = '\0'; 81436285Sbrian dl->phone.next = NULL; 81536285Sbrian dl->phone.alt = NULL; 81636285Sbrian dl->phone.chosen = "N/A"; 81737007Sbrian dl->stayonline = 0; 81836285Sbrian dl->script.run = 1; 81936285Sbrian dl->script.packetmode = 1; 82036285Sbrian mp_linkInit(&dl->mp); 82136285Sbrian 82236285Sbrian dl->bundle = bundle; 82336285Sbrian dl->next = NULL; 82436285Sbrian 82544468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 82636285Sbrian 82744468Sbrian dl->dial.tries = 0; 82836285Sbrian dl->cfg.dial.max = 1; 82936285Sbrian dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 83036285Sbrian dl->cfg.dial.timeout = DIAL_TIMEOUT; 83144468Sbrian dl->cfg.dial.inc = 0; 83244468Sbrian dl->cfg.dial.maxinc = 10; 83336285Sbrian 83436285Sbrian dl->reconnect_tries = 0; 83536285Sbrian dl->cfg.reconnect.max = 0; 83636285Sbrian dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 83736285Sbrian 83838174Sbrian dl->cfg.callback.opmask = 0; 83938174Sbrian dl->cfg.cbcp.delay = 0; 84038174Sbrian *dl->cfg.cbcp.phone = '\0'; 84138174Sbrian dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 84238174Sbrian 84336285Sbrian dl->name = strdup(name); 84436285Sbrian peerid_Init(&dl->peer); 84536285Sbrian dl->parent = &bundle->fsm; 84636285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 84736285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 84836285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 84936285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 85036285Sbrian dl->fsmp.object = dl; 85136285Sbrian 85246686Sbrian if ((dl->physical = physical_Create(dl, type)) == NULL) { 85336285Sbrian free(dl->name); 85436285Sbrian free(dl); 85536285Sbrian return NULL; 85636285Sbrian } 85743693Sbrian 85843693Sbrian pap_Init(&dl->pap, dl->physical); 85943693Sbrian chap_Init(&dl->chap, dl->physical); 86038174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 86136285Sbrian 86252488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 86354055Sbrian chat_Init(&dl->chat, dl->physical); 86452488Sbrian 86536285Sbrian log_Printf(LogPHASE, "%s: Created in %s state\n", 86636285Sbrian dl->name, datalink_State(dl)); 86736285Sbrian 86836285Sbrian return dl; 86936285Sbrian} 87036285Sbrian 87136285Sbrianstruct datalink * 87236285Sbriandatalink_Clone(struct datalink *odl, const char *name) 87336285Sbrian{ 87436285Sbrian struct datalink *dl; 87536285Sbrian 87636285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 87736285Sbrian if (dl == NULL) 87836285Sbrian return dl; 87936285Sbrian 88036285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 88136285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 88236285Sbrian dl->desc.IsSet = datalink_IsSet; 88336285Sbrian dl->desc.Read = datalink_Read; 88436285Sbrian dl->desc.Write = datalink_Write; 88536285Sbrian 88636285Sbrian dl->state = DATALINK_CLOSED; 88736285Sbrian 88836285Sbrian memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 88936285Sbrian mp_linkInit(&dl->mp); 89036285Sbrian *dl->phone.list = '\0'; 89136285Sbrian dl->phone.next = NULL; 89236285Sbrian dl->phone.alt = NULL; 89336285Sbrian dl->phone.chosen = "N/A"; 89436285Sbrian dl->bundle = odl->bundle; 89536285Sbrian dl->next = NULL; 89644468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 89744468Sbrian dl->dial.tries = 0; 89836285Sbrian dl->reconnect_tries = 0; 89936285Sbrian dl->name = strdup(name); 90036285Sbrian peerid_Init(&dl->peer); 90136285Sbrian dl->parent = odl->parent; 90236285Sbrian memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 90336285Sbrian dl->fsmp.object = dl; 90436285Sbrian 90546686Sbrian if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { 90636285Sbrian free(dl->name); 90736285Sbrian free(dl); 90836285Sbrian return NULL; 90936285Sbrian } 91043693Sbrian pap_Init(&dl->pap, dl->physical); 91144305Sbrian dl->pap.cfg = odl->pap.cfg; 91243693Sbrian 91343693Sbrian chap_Init(&dl->chap, dl->physical); 91444305Sbrian dl->chap.auth.cfg = odl->chap.auth.cfg; 91543693Sbrian 91636285Sbrian memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 91736285Sbrian memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 91836285Sbrian sizeof dl->physical->link.lcp.cfg); 91936285Sbrian memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 92036285Sbrian sizeof dl->physical->link.ccp.cfg); 92136285Sbrian memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 92236285Sbrian sizeof dl->physical->async.cfg); 92336285Sbrian 92438174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 92536285Sbrian 92652488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 92754055Sbrian chat_Init(&dl->chat, dl->physical); 92852488Sbrian 92936285Sbrian log_Printf(LogPHASE, "%s: Cloned in %s state\n", 93036285Sbrian dl->name, datalink_State(dl)); 93136285Sbrian 93236285Sbrian return dl; 93336285Sbrian} 93436285Sbrian 93536285Sbrianstruct datalink * 93636285Sbriandatalink_Destroy(struct datalink *dl) 93736285Sbrian{ 93836285Sbrian struct datalink *result; 93936285Sbrian 94036285Sbrian if (dl->state != DATALINK_CLOSED) { 94136285Sbrian log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 94236285Sbrian datalink_State(dl)); 94336285Sbrian switch (dl->state) { 94436285Sbrian case DATALINK_HANGUP: 94536285Sbrian case DATALINK_DIAL: 94636285Sbrian case DATALINK_LOGIN: 94754055Sbrian chat_Finish(&dl->chat); /* Gotta blat the timers ! */ 94836285Sbrian break; 94936285Sbrian } 95036285Sbrian } 95136285Sbrian 95254055Sbrian chat_Destroy(&dl->chat); 95344468Sbrian timer_Stop(&dl->dial.timer); 95436285Sbrian result = dl->next; 95546686Sbrian physical_Destroy(dl->physical); 95636285Sbrian free(dl->name); 95736285Sbrian free(dl); 95836285Sbrian 95936285Sbrian return result; 96036285Sbrian} 96136285Sbrian 96236285Sbrianvoid 96336285Sbriandatalink_Up(struct datalink *dl, int runscripts, int packetmode) 96436285Sbrian{ 965112659Sbrian if (!Enabled(dl->bundle, OPT_FORCE_SCRIPTS) && 966112659Sbrian (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))) 96736285Sbrian /* Ignore scripts */ 96836285Sbrian runscripts = 0; 96936285Sbrian 97036285Sbrian switch (dl->state) { 97136285Sbrian case DATALINK_CLOSED: 97236285Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 97336285Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 97436285Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 97536285Sbrian datalink_NewState(dl, DATALINK_OPENING); 97636285Sbrian dl->reconnect_tries = 97736285Sbrian dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 97844468Sbrian dl->dial.tries = dl->cfg.dial.max; 97936285Sbrian dl->script.run = runscripts; 98036285Sbrian dl->script.packetmode = packetmode; 98136285Sbrian break; 98236285Sbrian 98336285Sbrian case DATALINK_OPENING: 98436285Sbrian if (!dl->script.run && runscripts) 98536285Sbrian dl->script.run = 1; 986102413Scharnier /* FALLTHROUGH */ 98736285Sbrian 98836285Sbrian case DATALINK_DIAL: 98936285Sbrian case DATALINK_LOGIN: 99036285Sbrian case DATALINK_READY: 99136285Sbrian if (!dl->script.packetmode && packetmode) { 99236285Sbrian dl->script.packetmode = 1; 99360945Sbrian if (dl->state == DATALINK_READY) { 99460945Sbrian dl->script.run = 0; 99560945Sbrian datalink_NewState(dl, DATALINK_CARRIER); 99660945Sbrian } 99736285Sbrian } 99836285Sbrian break; 99936285Sbrian } 100036285Sbrian} 100136285Sbrian 100236285Sbrianvoid 100337007Sbriandatalink_Close(struct datalink *dl, int how) 100436285Sbrian{ 100536285Sbrian /* Please close */ 100636285Sbrian switch (dl->state) { 100736285Sbrian case DATALINK_OPEN: 100836285Sbrian peerid_Init(&dl->peer); 100937060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 1010102413Scharnier /* FALLTHROUGH */ 101136285Sbrian 101238174Sbrian case DATALINK_CBCP: 101336285Sbrian case DATALINK_AUTH: 101436285Sbrian case DATALINK_LCP: 101544094Sbrian datalink_AuthReInit(dl); 101671970Sbrian if (how == CLOSE_LCP) 101771970Sbrian datalink_DontHangup(dl); 101871970Sbrian else if (how == CLOSE_STAYDOWN) 101971970Sbrian datalink_StayDown(dl); 102036285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 102152029Sbrian break; 102236285Sbrian 102336285Sbrian default: 102437007Sbrian datalink_ComeDown(dl, how); 102536285Sbrian } 102636285Sbrian} 102736285Sbrian 102836285Sbrianvoid 102937007Sbriandatalink_Down(struct datalink *dl, int how) 103036285Sbrian{ 103136285Sbrian /* Carrier is lost */ 103236285Sbrian switch (dl->state) { 103336285Sbrian case DATALINK_OPEN: 103436285Sbrian peerid_Init(&dl->peer); 103537060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 1036102413Scharnier /* FALLTHROUGH */ 103736285Sbrian 103838174Sbrian case DATALINK_CBCP: 103936285Sbrian case DATALINK_AUTH: 104036285Sbrian case DATALINK_LCP: 104137060Sbrian fsm2initial(&dl->physical->link.lcp.fsm); 104256656Sbrian if (dl->state == DATALINK_OPENING) 104356656Sbrian return; /* we're doing a callback... */ 1044102413Scharnier /* FALLTHROUGH */ 104536285Sbrian 104636285Sbrian default: 104737007Sbrian datalink_ComeDown(dl, how); 104836285Sbrian } 104936285Sbrian} 105036285Sbrian 105136285Sbrianvoid 105236285Sbriandatalink_StayDown(struct datalink *dl) 105336285Sbrian{ 105471970Sbrian dl->dial.tries = -1; 105536285Sbrian dl->reconnect_tries = 0; 105671970Sbrian dl->stayonline = 0; 105736285Sbrian} 105836285Sbrian 105937007Sbrianvoid 106037007Sbriandatalink_DontHangup(struct datalink *dl) 106137007Sbrian{ 106271970Sbrian dl->dial.tries = -1; 106371970Sbrian dl->reconnect_tries = 0; 106471970Sbrian dl->stayonline = dl->state >= DATALINK_LCP ? 1 : 0; 106537007Sbrian} 106637007Sbrian 106736285Sbrianint 106836285Sbriandatalink_Show(struct cmdargs const *arg) 106936285Sbrian{ 107036285Sbrian prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 107138174Sbrian prompt_Printf(arg->prompt, " State: %s\n", 107236285Sbrian datalink_State(arg->cx)); 107338174Sbrian prompt_Printf(arg->prompt, " Peer name: "); 107436285Sbrian if (*arg->cx->peer.authname) 107536285Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 107636285Sbrian else if (arg->cx->state == DATALINK_OPEN) 107736285Sbrian prompt_Printf(arg->prompt, "None requested\n"); 107836285Sbrian else 107936285Sbrian prompt_Printf(arg->prompt, "N/A\n"); 108038174Sbrian prompt_Printf(arg->prompt, " Discriminator: %s\n", 108136285Sbrian mp_Enddisc(arg->cx->peer.enddisc.class, 108236285Sbrian arg->cx->peer.enddisc.address, 108336285Sbrian arg->cx->peer.enddisc.len)); 108436285Sbrian 108536285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 108638174Sbrian prompt_Printf(arg->prompt, " Phone List: %s\n", 108736285Sbrian arg->cx->cfg.phone.list); 108836285Sbrian if (arg->cx->cfg.dial.max) 108938174Sbrian prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 109036285Sbrian arg->cx->cfg.dial.max); 109136285Sbrian else 109238174Sbrian prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 109344261Sbrian if (arg->cx->cfg.dial.next_timeout >= 0) 109436285Sbrian prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 109536285Sbrian else 109636285Sbrian prompt_Printf(arg->prompt, "random/"); 109744261Sbrian if (arg->cx->cfg.dial.timeout >= 0) 109836285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 109936285Sbrian else 110036285Sbrian prompt_Printf(arg->prompt, "random\n"); 110138174Sbrian prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 110236285Sbrian arg->cx->cfg.reconnect.max); 110336285Sbrian if (arg->cx->cfg.reconnect.timeout > 0) 110436285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 110536285Sbrian else 110636285Sbrian prompt_Printf(arg->prompt, "random\n"); 110738174Sbrian prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 110838174Sbrian PHYS_DIRECT ? "accepted: " : "requested:"); 110938174Sbrian if (!arg->cx->cfg.callback.opmask) 111038174Sbrian prompt_Printf(arg->prompt, "none\n"); 111138174Sbrian else { 111238174Sbrian int comma = 0; 111338174Sbrian 111438174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 111538174Sbrian prompt_Printf(arg->prompt, "none"); 111638174Sbrian comma = 1; 111738174Sbrian } 111838174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 111938174Sbrian prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 112038174Sbrian comma = 1; 112138174Sbrian } 112238174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 112338174Sbrian prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 112438174Sbrian if (arg->cx->physical->type != PHYS_DIRECT) 112538174Sbrian prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 112638174Sbrian comma = 1; 112738174Sbrian } 112838174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 112938174Sbrian prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 113038174Sbrian prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 113138174Sbrian arg->cx->cfg.cbcp.delay); 113240483Sbrian prompt_Printf(arg->prompt, " phone: "); 113340483Sbrian if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 113440483Sbrian if (arg->cx->physical->type & PHYS_DIRECT) 113540483Sbrian prompt_Printf(arg->prompt, "Caller decides\n"); 113640483Sbrian else 113740483Sbrian prompt_Printf(arg->prompt, "Dialback server decides\n"); 113840483Sbrian } else 113940483Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 114038174Sbrian prompt_Printf(arg->prompt, " timeout: %lds\n", 114138174Sbrian arg->cx->cfg.cbcp.fsmretry); 114238174Sbrian } else 114338174Sbrian prompt_Printf(arg->prompt, "\n"); 114438174Sbrian } 114538174Sbrian 114638174Sbrian prompt_Printf(arg->prompt, " Dial Script: %s\n", 114736285Sbrian arg->cx->cfg.script.dial); 114838174Sbrian prompt_Printf(arg->prompt, " Login Script: %s\n", 114936285Sbrian arg->cx->cfg.script.login); 115052488Sbrian prompt_Printf(arg->prompt, " Logout Script: %s\n", 115152488Sbrian arg->cx->cfg.script.logout); 115238174Sbrian prompt_Printf(arg->prompt, " Hangup Script: %s\n", 115336285Sbrian arg->cx->cfg.script.hangup); 115436285Sbrian return 0; 115536285Sbrian} 115636285Sbrian 115736285Sbrianint 115836285Sbriandatalink_SetReconnect(struct cmdargs const *arg) 115936285Sbrian{ 116036285Sbrian if (arg->argc == arg->argn+2) { 116136285Sbrian arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 116236285Sbrian arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 116336285Sbrian return 0; 116436285Sbrian } 116536285Sbrian return -1; 116636285Sbrian} 116736285Sbrian 116836285Sbrianint 116936285Sbriandatalink_SetRedial(struct cmdargs const *arg) 117036285Sbrian{ 117144468Sbrian const char *sep, *osep; 117244468Sbrian int timeout, inc, maxinc, tries; 117336285Sbrian 117436285Sbrian if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 117536285Sbrian if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 117636285Sbrian (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 117736285Sbrian arg->cx->cfg.dial.timeout = -1; 117836285Sbrian randinit(); 117936285Sbrian } else { 118036285Sbrian timeout = atoi(arg->argv[arg->argn]); 118136285Sbrian 118236285Sbrian if (timeout >= 0) 118336285Sbrian arg->cx->cfg.dial.timeout = timeout; 118436285Sbrian else { 118536285Sbrian log_Printf(LogWARN, "Invalid redial timeout\n"); 118636285Sbrian return -1; 118736285Sbrian } 118836285Sbrian } 118936285Sbrian 119044468Sbrian sep = strchr(arg->argv[arg->argn], '+'); 119144468Sbrian if (sep) { 119244468Sbrian inc = atoi(++sep); 119344468Sbrian osep = sep; 119444468Sbrian if (inc >= 0) 119544468Sbrian arg->cx->cfg.dial.inc = inc; 119644468Sbrian else { 119744468Sbrian log_Printf(LogWARN, "Invalid timeout increment\n"); 119844468Sbrian return -1; 119944468Sbrian } 120044468Sbrian sep = strchr(sep, '-'); 120144468Sbrian if (sep) { 120244468Sbrian maxinc = atoi(++sep); 120344468Sbrian if (maxinc >= 0) 120444468Sbrian arg->cx->cfg.dial.maxinc = maxinc; 120544468Sbrian else { 120644468Sbrian log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 120744468Sbrian return -1; 120844468Sbrian } 120944468Sbrian } else { 121044468Sbrian /* Default timeout increment */ 121144468Sbrian arg->cx->cfg.dial.maxinc = 10; 121244468Sbrian sep = osep; 121344468Sbrian } 121444468Sbrian } else { 121544468Sbrian /* Default timeout increment & max increment */ 121644468Sbrian arg->cx->cfg.dial.inc = 0; 121744468Sbrian arg->cx->cfg.dial.maxinc = 10; 121844468Sbrian sep = arg->argv[arg->argn]; 121944468Sbrian } 122044468Sbrian 122144468Sbrian sep = strchr(sep, '.'); 122244468Sbrian if (sep) { 122344468Sbrian if (strcasecmp(++sep, "random") == 0) { 122436285Sbrian arg->cx->cfg.dial.next_timeout = -1; 122536285Sbrian randinit(); 122636285Sbrian } else { 122744468Sbrian timeout = atoi(sep); 122836285Sbrian if (timeout >= 0) 122936285Sbrian arg->cx->cfg.dial.next_timeout = timeout; 123036285Sbrian else { 123136285Sbrian log_Printf(LogWARN, "Invalid next redial timeout\n"); 123236285Sbrian return -1; 123336285Sbrian } 123436285Sbrian } 123536285Sbrian } else 123636285Sbrian /* Default next timeout */ 123736285Sbrian arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 123836285Sbrian 123936285Sbrian if (arg->argc == arg->argn+2) { 124036285Sbrian tries = atoi(arg->argv[arg->argn+1]); 124136285Sbrian 124236285Sbrian if (tries >= 0) { 124336285Sbrian arg->cx->cfg.dial.max = tries; 124436285Sbrian } else { 124536285Sbrian log_Printf(LogWARN, "Invalid retry value\n"); 124636285Sbrian return 1; 124736285Sbrian } 124836285Sbrian } 124936285Sbrian return 0; 125036285Sbrian } 125144468Sbrian 125236285Sbrian return -1; 125336285Sbrian} 125436285Sbrian 125555146Sbrianstatic const char * const states[] = { 125636285Sbrian "closed", 125736285Sbrian "opening", 125836285Sbrian "hangup", 125936285Sbrian "dial", 126049472Sbrian "carrier", 126152488Sbrian "logout", 126236285Sbrian "login", 126336285Sbrian "ready", 126436285Sbrian "lcp", 126536285Sbrian "auth", 126638174Sbrian "cbcp", 126736285Sbrian "open" 126836285Sbrian}; 126936285Sbrian 127036285Sbrianconst char * 127136285Sbriandatalink_State(struct datalink *dl) 127236285Sbrian{ 1273134789Sbrian if (dl->state >= sizeof states / sizeof states[0]) 127436285Sbrian return "unknown"; 127536285Sbrian return states[dl->state]; 127636285Sbrian} 127736285Sbrian 127836285Sbrianstatic void 1279134789Sbriandatalink_NewState(struct datalink *dl, unsigned state) 128036285Sbrian{ 128136285Sbrian if (state != dl->state) { 1282134789Sbrian if (state < sizeof states / sizeof states[0]) { 128336285Sbrian log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 128436285Sbrian states[state]); 128536285Sbrian dl->state = state; 128636285Sbrian } else 128736285Sbrian log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 128836285Sbrian } 128936285Sbrian} 129036285Sbrian 129136285Sbrianstruct datalink * 129236285Sbrianiov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 129352942Sbrian int fd, int *auxfd, int *nauxfd) 129436285Sbrian{ 129536285Sbrian struct datalink *dl, *cdl; 129644305Sbrian struct fsm_retry copy; 1297136375Sbrian char *oname, *pname; 129836285Sbrian 129936285Sbrian dl = (struct datalink *)iov[(*niov)++].iov_base; 130036285Sbrian dl->name = iov[*niov].iov_base; 130136285Sbrian 130236285Sbrian if (dl->name[DATALINK_MAXNAME-1]) { 130336285Sbrian dl->name[DATALINK_MAXNAME-1] = '\0'; 130436285Sbrian if (strlen(dl->name) == DATALINK_MAXNAME - 1) 130536285Sbrian log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 130636285Sbrian } 130736285Sbrian 130836285Sbrian /* Make sure the name is unique ! */ 130936285Sbrian oname = NULL; 131036285Sbrian do { 131136285Sbrian for (cdl = bundle->links; cdl; cdl = cdl->next) 131236285Sbrian if (!strcasecmp(dl->name, cdl->name)) { 1313136375Sbrian if ((pname = datalink_NextName(dl)) == NULL) { 1314136375Sbrian for ((*niov)--; *niov < maxiov; (*niov)++) 1315136375Sbrian free(iov[*niov].iov_base); 1316136375Sbrian return NULL; 1317136375Sbrian } else if (oname) 1318136375Sbrian free(pname); 131936285Sbrian else 1320136375Sbrian oname = pname; 132136285Sbrian break; /* Keep renaming 'till we have no conflicts */ 132236285Sbrian } 132336285Sbrian } while (cdl); 132436285Sbrian 132536285Sbrian if (oname) { 132636285Sbrian log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 132736285Sbrian free(oname); 132836285Sbrian } else { 132936285Sbrian dl->name = strdup(dl->name); 133036285Sbrian free(iov[*niov].iov_base); 133136285Sbrian } 133236285Sbrian (*niov)++; 133336285Sbrian 133436285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 133536285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 133636285Sbrian dl->desc.IsSet = datalink_IsSet; 133736285Sbrian dl->desc.Read = datalink_Read; 133836285Sbrian dl->desc.Write = datalink_Write; 133936285Sbrian 134036285Sbrian mp_linkInit(&dl->mp); 134136285Sbrian *dl->phone.list = '\0'; 134236285Sbrian dl->phone.next = NULL; 134336285Sbrian dl->phone.alt = NULL; 134436285Sbrian dl->phone.chosen = "N/A"; 134536285Sbrian 134636285Sbrian dl->bundle = bundle; 134736285Sbrian dl->next = NULL; 134844468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 134944468Sbrian dl->dial.tries = 0; 135036285Sbrian dl->reconnect_tries = 0; 135136285Sbrian dl->parent = &bundle->fsm; 135236285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 135336285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 135436285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 135536285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 135636285Sbrian dl->fsmp.object = dl; 135736285Sbrian 135852942Sbrian dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); 135936285Sbrian 136036285Sbrian if (!dl->physical) { 136136285Sbrian free(dl->name); 136236285Sbrian free(dl); 136336285Sbrian dl = NULL; 136436285Sbrian } else { 136544305Sbrian copy = dl->pap.cfg.fsm; 136643693Sbrian pap_Init(&dl->pap, dl->physical); 136744305Sbrian dl->pap.cfg.fsm = copy; 136843693Sbrian 136944305Sbrian copy = dl->chap.auth.cfg.fsm; 137043693Sbrian chap_Init(&dl->chap, dl->physical); 137144305Sbrian dl->chap.auth.cfg.fsm = copy; 137243693Sbrian 137338174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 137436285Sbrian 137552488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 137654055Sbrian chat_Init(&dl->chat, dl->physical); 137752488Sbrian 137836285Sbrian log_Printf(LogPHASE, "%s: Transferred in %s state\n", 137936285Sbrian dl->name, datalink_State(dl)); 138036285Sbrian } 138136285Sbrian 138236285Sbrian return dl; 138336285Sbrian} 138436285Sbrian 138536285Sbrianint 138636450Sbriandatalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 138753684Sbrian int *auxfd, int *nauxfd) 138836285Sbrian{ 138936285Sbrian /* If `dl' is NULL, we're allocating before a Fromiov() */ 139036285Sbrian int link_fd; 139136285Sbrian 139236285Sbrian if (dl) { 139344468Sbrian timer_Stop(&dl->dial.timer); 139438174Sbrian /* The following is purely for the sake of paranoia */ 139538174Sbrian cbcp_Down(&dl->cbcp); 139636285Sbrian timer_Stop(&dl->pap.authtimer); 139736285Sbrian timer_Stop(&dl->chap.auth.authtimer); 139836285Sbrian } 139936285Sbrian 140036285Sbrian if (*niov >= maxiov - 1) { 140136285Sbrian log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 140236285Sbrian if (dl) { 140336285Sbrian free(dl->name); 140436285Sbrian free(dl); 140536285Sbrian } 140636285Sbrian return -1; 140736285Sbrian } 140836285Sbrian 140953684Sbrian iov[*niov].iov_base = (void *)dl; 141036285Sbrian iov[(*niov)++].iov_len = sizeof *dl; 141153684Sbrian iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL; 141236285Sbrian iov[(*niov)++].iov_len = DATALINK_MAXNAME; 141336285Sbrian 141452942Sbrian link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, 141553684Sbrian nauxfd); 141636285Sbrian 141736285Sbrian if (link_fd == -1 && dl) { 141836285Sbrian free(dl->name); 141936285Sbrian free(dl); 142036285Sbrian } 142136285Sbrian 142236285Sbrian return link_fd; 142336285Sbrian} 142436285Sbrian 142536285Sbrianvoid 142636285Sbriandatalink_Rename(struct datalink *dl, const char *name) 142736285Sbrian{ 142836285Sbrian free(dl->name); 142936285Sbrian dl->physical->link.name = dl->name = strdup(name); 143036285Sbrian} 143136285Sbrian 1432136375Sbrianstatic char * 143336285Sbriandatalink_NextName(struct datalink *dl) 143436285Sbrian{ 143536285Sbrian int f, n; 143636285Sbrian char *name, *oname; 143736285Sbrian 143836285Sbrian n = strlen(dl->name); 1439136375Sbrian if ((name = (char *)malloc(n+3)) == NULL) { 1440136375Sbrian log_Printf(LogERROR, "datalink_NextName: Out of memory !\n"); 1441136375Sbrian return NULL; 1442136375Sbrian } 144336285Sbrian for (f = n - 1; f >= 0; f--) 144436285Sbrian if (!isdigit(dl->name[f])) 144536285Sbrian break; 144636285Sbrian n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 144736285Sbrian sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 144836285Sbrian oname = dl->name; 144936345Sbrian dl->name = name; 145036345Sbrian /* our physical link name isn't updated (it probably isn't created yet) */ 145136285Sbrian return oname; 145236285Sbrian} 145336285Sbrian 145436285Sbrianint 145536285Sbriandatalink_SetMode(struct datalink *dl, int mode) 145636285Sbrian{ 145736285Sbrian if (!physical_SetMode(dl->physical, mode)) 145836285Sbrian return 0; 145936285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 146036285Sbrian dl->script.run = 0; 146136285Sbrian if (dl->physical->type == PHYS_DIRECT) 146236285Sbrian dl->reconnect_tries = 0; 146353830Sbrian if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) && 146453830Sbrian dl->state <= DATALINK_READY) 146536285Sbrian datalink_Up(dl, 1, 1); 146636285Sbrian return 1; 146736285Sbrian} 146844468Sbrian 146944468Sbrianint 147044468Sbriandatalink_GetDialTimeout(struct datalink *dl) 147144468Sbrian{ 147244468Sbrian int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 147344468Sbrian 147444468Sbrian if (dl->dial.incs < dl->cfg.dial.maxinc) 147544468Sbrian dl->dial.incs++; 147644468Sbrian 147744468Sbrian return result; 147844468Sbrian} 1479