datalink.c revision 67912
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: head/usr.sbin/ppp/datalink.c 67912 2000-10-30 00:15:29Z brian $ 2736285Sbrian */ 2836285Sbrian 2943313Sbrian#include <sys/param.h> 3036285Sbrian#include <netinet/in.h> 3136285Sbrian#include <netinet/in_systm.h> 3236285Sbrian#include <netinet/ip.h> 3336285Sbrian#include <sys/un.h> 3436285Sbrian 3536285Sbrian#include <ctype.h> 3636285Sbrian#include <stdio.h> 3736285Sbrian#include <stdlib.h> 3836285Sbrian#include <string.h> 3936285Sbrian#include <sys/uio.h> 4036285Sbrian#include <termios.h> 4136285Sbrian 4246686Sbrian#include "layer.h" 4336285Sbrian#include "mbuf.h" 4436285Sbrian#include "log.h" 4536285Sbrian#include "defs.h" 4636285Sbrian#include "timer.h" 4736285Sbrian#include "fsm.h" 4836285Sbrian#include "descriptor.h" 4936285Sbrian#include "lqr.h" 5036285Sbrian#include "hdlc.h" 5163484Sbrian#include "lcp.h" 5236285Sbrian#include "async.h" 5336285Sbrian#include "throughput.h" 5436285Sbrian#include "ccp.h" 5536285Sbrian#include "link.h" 5636285Sbrian#include "physical.h" 5736285Sbrian#include "iplist.h" 5836285Sbrian#include "slcompress.h" 5936285Sbrian#include "ipcp.h" 6036285Sbrian#include "filter.h" 6136285Sbrian#include "mp.h" 6243313Sbrian#ifndef NORADIUS 6343313Sbrian#include "radius.h" 6443313Sbrian#endif 6536285Sbrian#include "bundle.h" 6636285Sbrian#include "chat.h" 6736285Sbrian#include "auth.h" 6836285Sbrian#include "prompt.h" 6946686Sbrian#include "proto.h" 7036285Sbrian#include "pap.h" 7136285Sbrian#include "chap.h" 7236285Sbrian#include "command.h" 7338174Sbrian#include "cbcp.h" 7436285Sbrian#include "datalink.h" 7536285Sbrian 7636285Sbrianstatic void datalink_LoginDone(struct datalink *); 7736285Sbrianstatic void datalink_NewState(struct datalink *, int); 7836285Sbrian 7936285Sbrianstatic void 8036285Sbriandatalink_OpenTimeout(void *v) 8136285Sbrian{ 8236285Sbrian struct datalink *dl = (struct datalink *)v; 8336285Sbrian 8444468Sbrian timer_Stop(&dl->dial.timer); 8536285Sbrian if (dl->state == DATALINK_OPENING) 8659084Sbrian log_Printf(LogCHAT, "%s: Redial timer expired.\n", dl->name); 8736285Sbrian} 8836285Sbrian 8944261Sbrianstatic int 9036285Sbriandatalink_StartDialTimer(struct datalink *dl, int Timeout) 9136285Sbrian{ 9244261Sbrian int result = Timeout; 9344261Sbrian 9444468Sbrian timer_Stop(&dl->dial.timer); 9538174Sbrian if (Timeout) { 9636285Sbrian if (Timeout > 0) 9744468Sbrian dl->dial.timer.load = Timeout * SECTICKS; 9844261Sbrian else { 9944261Sbrian result = (random() % DIAL_TIMEOUT) + 1; 10044468Sbrian dl->dial.timer.load = result * SECTICKS; 10144261Sbrian } 10244468Sbrian dl->dial.timer.func = datalink_OpenTimeout; 10344468Sbrian dl->dial.timer.name = "dial"; 10444468Sbrian dl->dial.timer.arg = dl; 10544468Sbrian timer_Start(&dl->dial.timer); 10636285Sbrian if (dl->state == DATALINK_OPENING) 10736285Sbrian log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 10836285Sbrian dl->name, Timeout); 10936285Sbrian } 11044261Sbrian return result; 11136285Sbrian} 11236285Sbrian 11336285Sbrianstatic void 11436285Sbriandatalink_HangupDone(struct datalink *dl) 11536285Sbrian{ 11636285Sbrian if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 11746686Sbrian dl->physical->fd != -1) { 11846686Sbrian /* Don't close our device if the link is dedicated */ 11936285Sbrian datalink_LoginDone(dl); 12036285Sbrian return; 12136285Sbrian } 12236285Sbrian 12354055Sbrian chat_Finish(&dl->chat); 12446686Sbrian physical_Close(dl->physical); 12536285Sbrian dl->phone.chosen = "N/A"; 12636285Sbrian 12738174Sbrian if (dl->cbcp.required) { 12838174Sbrian log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 12938174Sbrian dl->cfg.callback.opmask = 0; 13038174Sbrian strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 13138174Sbrian sizeof dl->cfg.phone.list - 1); 13238174Sbrian dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 13338174Sbrian dl->phone.alt = dl->phone.next = NULL; 13438174Sbrian dl->reconnect_tries = dl->cfg.reconnect.max; 13544468Sbrian dl->dial.tries = dl->cfg.dial.max; 13644468Sbrian dl->dial.incs = 0; 13738174Sbrian dl->script.run = 1; 13838174Sbrian dl->script.packetmode = 1; 13938174Sbrian if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 14038174Sbrian log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 14138174Sbrian bundle_LinksRemoved(dl->bundle); 14244468Sbrian /* if dial.timeout is < 0 (random), we don't override fsm.delay */ 14338174Sbrian if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 14438174Sbrian dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 14538174Sbrian datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 14638174Sbrian cbcp_Down(&dl->cbcp); 14738174Sbrian datalink_NewState(dl, DATALINK_OPENING); 14852412Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 14952412Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 15045385Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 15138174Sbrian } else if (dl->bundle->CleaningUp || 15236285Sbrian (dl->physical->type == PHYS_DIRECT) || 15344468Sbrian ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15436465Sbrian !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 15536285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 15644468Sbrian dl->dial.tries = -1; 15744468Sbrian dl->dial.incs = 0; 15836285Sbrian dl->reconnect_tries = 0; 15936285Sbrian bundle_LinkClosed(dl->bundle, dl); 16058455Sbrian if (!dl->bundle->CleaningUp && 16158455Sbrian !(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND))) 16244468Sbrian datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 16336285Sbrian } else { 16436285Sbrian datalink_NewState(dl, DATALINK_OPENING); 16552412Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 16652412Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 16745385Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 16844468Sbrian if (dl->dial.tries < 0) { 16936285Sbrian datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 17044468Sbrian dl->dial.tries = dl->cfg.dial.max; 17144468Sbrian dl->dial.incs = 0; 17236285Sbrian dl->reconnect_tries--; 17359084Sbrian log_Printf(LogCHAT, "%s: Reconnect try %d of %d\n", 17459084Sbrian dl->name, dl->cfg.reconnect.max - dl->reconnect_tries, 17559084Sbrian dl->cfg.reconnect.max); 17659084Sbrian bundle_Notify(dl->bundle, EX_RECONNECT); 17736285Sbrian } else { 17836285Sbrian if (dl->phone.next == NULL) 17944468Sbrian datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 18036285Sbrian else 18136285Sbrian datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 18259084Sbrian bundle_Notify(dl->bundle, EX_REDIAL); 18336285Sbrian } 18436285Sbrian } 18536285Sbrian} 18636285Sbrian 18749472Sbrianconst char * 18836285Sbriandatalink_ChoosePhoneNumber(struct datalink *dl) 18936285Sbrian{ 19036285Sbrian char *phone; 19136285Sbrian 19236285Sbrian if (dl->phone.alt == NULL) { 19336285Sbrian if (dl->phone.next == NULL) { 19436285Sbrian strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 19536285Sbrian dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 19648003Sbrian if (*dl->phone.list == '\0') 19748003Sbrian return ""; 19836285Sbrian dl->phone.next = dl->phone.list; 19936285Sbrian } 20036285Sbrian dl->phone.alt = strsep(&dl->phone.next, ":"); 20136285Sbrian } 20236285Sbrian phone = strsep(&dl->phone.alt, "|"); 20336285Sbrian dl->phone.chosen = *phone ? phone : "[NONE]"; 20436285Sbrian if (*phone) 20559084Sbrian log_Printf(LogCHAT, "Phone: %s\n", phone); 20636285Sbrian return phone; 20736285Sbrian} 20836285Sbrian 20936285Sbrianstatic void 21036285Sbriandatalink_LoginDone(struct datalink *dl) 21136285Sbrian{ 21254055Sbrian chat_Finish(&dl->chat); 21352488Sbrian 21436285Sbrian if (!dl->script.packetmode) { 21544468Sbrian dl->dial.tries = -1; 21644468Sbrian dl->dial.incs = 0; 21736285Sbrian datalink_NewState(dl, DATALINK_READY); 21846686Sbrian } else if (!physical_Raw(dl->physical)) { 21944468Sbrian dl->dial.tries = 0; 22036285Sbrian log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 22136285Sbrian if (dl->script.run) { 22252488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 22354914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 22454914Sbrian log_Printf(LogWARN, "Invalid logout script\n"); 22536285Sbrian } else { 22647061Sbrian physical_StopDeviceTimer(dl->physical); 22736285Sbrian if (dl->physical->type == PHYS_DEDICATED) 22836285Sbrian /* force a redial timeout */ 22946686Sbrian physical_Close(dl->physical); 23036285Sbrian datalink_HangupDone(dl); 23136285Sbrian } 23236285Sbrian } else { 23344468Sbrian dl->dial.tries = -1; 23444468Sbrian dl->dial.incs = 0; 23536285Sbrian 23636285Sbrian hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 23736285Sbrian async_Init(&dl->physical->async); 23836285Sbrian 23936285Sbrian lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 24036285Sbrian 0 : dl->physical->link.lcp.cfg.openmode); 24136285Sbrian ccp_Setup(&dl->physical->link.ccp); 24236285Sbrian 24336285Sbrian datalink_NewState(dl, DATALINK_LCP); 24436285Sbrian fsm_Up(&dl->physical->link.lcp.fsm); 24536285Sbrian fsm_Open(&dl->physical->link.lcp.fsm); 24636285Sbrian } 24736285Sbrian} 24836285Sbrian 24936285Sbrianstatic int 25058028Sbriandatalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, 25136285Sbrian int *n) 25236285Sbrian{ 25336285Sbrian struct datalink *dl = descriptor2datalink(d); 25436285Sbrian int result; 25536285Sbrian 25636285Sbrian result = 0; 25736285Sbrian switch (dl->state) { 25836285Sbrian case DATALINK_CLOSED: 25953830Sbrian if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND| 26053830Sbrian PHYS_FOREGROUND|PHYS_DDIAL)) && 26147863Sbrian !dl->bundle->CleaningUp) 26236285Sbrian /* 26336465Sbrian * Our first time in - DEDICATED & DDIAL never come down, and 26453830Sbrian * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter 26553830Sbrian * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up() 26653830Sbrian * and fall through. 26736285Sbrian */ 26836285Sbrian datalink_Up(dl, 1, 1); 26936285Sbrian else 27036285Sbrian break; 27136285Sbrian /* fall through */ 27236285Sbrian 27336285Sbrian case DATALINK_OPENING: 27444468Sbrian if (dl->dial.timer.state != TIMER_RUNNING) { 27544468Sbrian if (--dl->dial.tries < 0) 27644468Sbrian dl->dial.tries = 0; 27746686Sbrian if (physical_Open(dl->physical, dl->bundle) >= 0) { 27838200Sbrian log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 27938200Sbrian "Type `~?' for help\r\n", dl->name, 28038200Sbrian dl->physical->name.full); 28136285Sbrian if (dl->script.run) { 28236285Sbrian datalink_NewState(dl, DATALINK_DIAL); 28354914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.dial, 28454914Sbrian *dl->cfg.script.dial ? 28554914Sbrian datalink_ChoosePhoneNumber(dl) : "")) 28654914Sbrian log_Printf(LogWARN, "Invalid dial script\n"); 28736465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 28836285Sbrian dl->cfg.dial.max) 28936285Sbrian log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 29044468Sbrian dl->name, dl->cfg.dial.max - dl->dial.tries, 29136285Sbrian dl->cfg.dial.max); 29236285Sbrian } else 29351978Sbrian datalink_NewState(dl, DATALINK_CARRIER); 29441830Sbrian return datalink_UpdateSet(d, r, w, e, n); 29536285Sbrian } else { 29636465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 29736285Sbrian dl->cfg.dial.max) 29846686Sbrian log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 29944468Sbrian dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 30036285Sbrian else 30146686Sbrian log_Printf(LogCHAT, "Failed to open device\n"); 30236285Sbrian 30336285Sbrian if (dl->bundle->CleaningUp || 30436465Sbrian (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 30544468Sbrian dl->cfg.dial.max && dl->dial.tries == 0)) { 30636285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 30736285Sbrian dl->reconnect_tries = 0; 30844468Sbrian dl->dial.tries = -1; 30938200Sbrian log_WritePrompts(dl, "Failed to open %s\n", 31038200Sbrian dl->physical->name.full); 31136285Sbrian bundle_LinkClosed(dl->bundle, dl); 31236285Sbrian } 31338200Sbrian if (!dl->bundle->CleaningUp) { 31444468Sbrian int timeout; 31544468Sbrian 31644468Sbrian timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 31759084Sbrian bundle_Notify(dl->bundle, EX_REDIAL); 31838200Sbrian log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 31944261Sbrian dl->physical->name.full, timeout); 32038200Sbrian } 32136285Sbrian } 32236285Sbrian } 32336285Sbrian break; 32436285Sbrian 32549472Sbrian case DATALINK_CARRIER: 32649472Sbrian /* Wait for carrier on the device */ 32749472Sbrian switch (physical_AwaitCarrier(dl->physical)) { 32849472Sbrian case CARRIER_PENDING: 32949472Sbrian log_Printf(LogDEBUG, "Waiting for carrier\n"); 33049472Sbrian return 0; /* A device timer is running to wake us up again */ 33149472Sbrian 33249472Sbrian case CARRIER_OK: 33351978Sbrian if (dl->script.run) { 33451978Sbrian datalink_NewState(dl, DATALINK_LOGIN); 33554914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL)) 33654914Sbrian log_Printf(LogWARN, "Invalid login script\n"); 33751978Sbrian } else 33851978Sbrian datalink_LoginDone(dl); 33949472Sbrian return datalink_UpdateSet(d, r, w, e, n); 34049472Sbrian 34149472Sbrian case CARRIER_LOST: 34249472Sbrian physical_Offline(dl->physical); /* Is this required ? */ 34351978Sbrian if (dl->script.run) { 34451978Sbrian datalink_NewState(dl, DATALINK_HANGUP); 34554914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 34654914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 34753070Sbrian return datalink_UpdateSet(d, r, w, e, n); 34853070Sbrian } else { 34951978Sbrian datalink_HangupDone(dl); 35053070Sbrian return 0; /* Maybe bundle_CleanDatalinks() has something to do */ 35153070Sbrian } 35249472Sbrian } 35349472Sbrian 35436285Sbrian case DATALINK_HANGUP: 35536285Sbrian case DATALINK_DIAL: 35652488Sbrian case DATALINK_LOGOUT: 35736285Sbrian case DATALINK_LOGIN: 35836285Sbrian result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 35936285Sbrian switch (dl->chat.state) { 36036285Sbrian case CHAT_DONE: 36136285Sbrian /* script succeeded */ 36236285Sbrian switch(dl->state) { 36336285Sbrian case DATALINK_HANGUP: 36436285Sbrian datalink_HangupDone(dl); 36536285Sbrian break; 36636285Sbrian case DATALINK_DIAL: 36749472Sbrian datalink_NewState(dl, DATALINK_CARRIER); 36836285Sbrian return datalink_UpdateSet(d, r, w, e, n); 36952488Sbrian case DATALINK_LOGOUT: 37052488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 37152488Sbrian physical_Offline(dl->physical); 37254914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 37354914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 37452488Sbrian return datalink_UpdateSet(d, r, w, e, n); 37536285Sbrian case DATALINK_LOGIN: 37642390Sbrian dl->phone.alt = NULL; 37736285Sbrian datalink_LoginDone(dl); 37842905Sbrian return datalink_UpdateSet(d, r, w, e, n); 37936285Sbrian } 38036285Sbrian break; 38136285Sbrian case CHAT_FAILED: 38236285Sbrian /* Going down - script failed */ 38336285Sbrian log_Printf(LogWARN, "Chat script failed\n"); 38436285Sbrian switch(dl->state) { 38536285Sbrian case DATALINK_HANGUP: 38636285Sbrian datalink_HangupDone(dl); 38736285Sbrian break; 38836285Sbrian case DATALINK_DIAL: 38952488Sbrian case DATALINK_LOGOUT: 39036285Sbrian case DATALINK_LOGIN: 39136285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 39252488Sbrian physical_Offline(dl->physical); 39354914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 39454914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 39536285Sbrian return datalink_UpdateSet(d, r, w, e, n); 39636285Sbrian } 39736285Sbrian break; 39836285Sbrian } 39936285Sbrian break; 40036285Sbrian 40136285Sbrian case DATALINK_READY: 40236285Sbrian case DATALINK_LCP: 40336285Sbrian case DATALINK_AUTH: 40438174Sbrian case DATALINK_CBCP: 40536285Sbrian case DATALINK_OPEN: 40643888Sbrian result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 40743888Sbrian descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 40836285Sbrian break; 40936285Sbrian } 41036285Sbrian return result; 41136285Sbrian} 41236285Sbrian 41336285Sbrianint 41436285Sbriandatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 41536285Sbrian{ 41636285Sbrian return physical_RemoveFromSet(dl->physical, r, w, e); 41736285Sbrian} 41836285Sbrian 41936285Sbrianstatic int 42058028Sbriandatalink_IsSet(struct fdescriptor *d, const fd_set *fdset) 42136285Sbrian{ 42236285Sbrian struct datalink *dl = descriptor2datalink(d); 42336285Sbrian 42436285Sbrian switch (dl->state) { 42536285Sbrian case DATALINK_CLOSED: 42636285Sbrian case DATALINK_OPENING: 42736285Sbrian break; 42836285Sbrian 42936285Sbrian case DATALINK_HANGUP: 43036285Sbrian case DATALINK_DIAL: 43152488Sbrian case DATALINK_LOGOUT: 43236285Sbrian case DATALINK_LOGIN: 43336285Sbrian return descriptor_IsSet(&dl->chat.desc, fdset); 43436285Sbrian 43536285Sbrian case DATALINK_READY: 43636285Sbrian case DATALINK_LCP: 43736285Sbrian case DATALINK_AUTH: 43838174Sbrian case DATALINK_CBCP: 43936285Sbrian case DATALINK_OPEN: 44043888Sbrian return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 44143888Sbrian descriptor_IsSet(&dl->physical->desc, fdset); 44236285Sbrian } 44336285Sbrian return 0; 44436285Sbrian} 44536285Sbrian 44636285Sbrianstatic void 44758028Sbriandatalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 44836285Sbrian{ 44936285Sbrian struct datalink *dl = descriptor2datalink(d); 45036285Sbrian 45136285Sbrian switch (dl->state) { 45236285Sbrian case DATALINK_CLOSED: 45336285Sbrian case DATALINK_OPENING: 45436285Sbrian break; 45536285Sbrian 45636285Sbrian case DATALINK_HANGUP: 45736285Sbrian case DATALINK_DIAL: 45852488Sbrian case DATALINK_LOGOUT: 45936285Sbrian case DATALINK_LOGIN: 46036285Sbrian descriptor_Read(&dl->chat.desc, bundle, fdset); 46136285Sbrian break; 46236285Sbrian 46336285Sbrian case DATALINK_READY: 46436285Sbrian case DATALINK_LCP: 46536285Sbrian case DATALINK_AUTH: 46638174Sbrian case DATALINK_CBCP: 46736285Sbrian case DATALINK_OPEN: 46843888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 46943888Sbrian descriptor_Read(&dl->chap.desc, bundle, fdset); 47043888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 47143888Sbrian descriptor_Read(&dl->physical->desc, bundle, fdset); 47236285Sbrian break; 47336285Sbrian } 47436285Sbrian} 47536285Sbrian 47637141Sbrianstatic int 47767912Sbriandatalink_Write(struct fdescriptor *d, struct bundle *bundle, 47867912Sbrian const fd_set *fdset) 47936285Sbrian{ 48036285Sbrian struct datalink *dl = descriptor2datalink(d); 48137141Sbrian int result = 0; 48236285Sbrian 48336285Sbrian switch (dl->state) { 48436285Sbrian case DATALINK_CLOSED: 48536285Sbrian case DATALINK_OPENING: 48636285Sbrian break; 48736285Sbrian 48836285Sbrian case DATALINK_HANGUP: 48936285Sbrian case DATALINK_DIAL: 49052488Sbrian case DATALINK_LOGOUT: 49136285Sbrian case DATALINK_LOGIN: 49237141Sbrian result = descriptor_Write(&dl->chat.desc, bundle, fdset); 49336285Sbrian break; 49436285Sbrian 49536285Sbrian case DATALINK_READY: 49636285Sbrian case DATALINK_LCP: 49736285Sbrian case DATALINK_AUTH: 49838174Sbrian case DATALINK_CBCP: 49936285Sbrian case DATALINK_OPEN: 50043888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 50143888Sbrian result += descriptor_Write(&dl->chap.desc, bundle, fdset); 50243888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 50343888Sbrian result += descriptor_Write(&dl->physical->desc, bundle, fdset); 50436285Sbrian break; 50536285Sbrian } 50637141Sbrian 50737141Sbrian return result; 50836285Sbrian} 50936285Sbrian 51036285Sbrianstatic void 51137007Sbriandatalink_ComeDown(struct datalink *dl, int how) 51236285Sbrian{ 51337007Sbrian if (how != CLOSE_NORMAL) { 51444468Sbrian dl->dial.tries = -1; 51536285Sbrian dl->reconnect_tries = 0; 51637012Sbrian if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 51737007Sbrian dl->stayonline = 1; 51836285Sbrian } 51936285Sbrian 52037012Sbrian if (dl->state >= DATALINK_READY && dl->stayonline) { 52137007Sbrian dl->stayonline = 0; 52247061Sbrian physical_StopDeviceTimer(dl->physical); 52337007Sbrian datalink_NewState(dl, DATALINK_READY); 52437007Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 52546686Sbrian physical_Offline(dl->physical); 52636285Sbrian if (dl->script.run && dl->state != DATALINK_OPENING) { 52752488Sbrian if (dl->state == DATALINK_LOGOUT) { 52852488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 52954914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 53054914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 53152488Sbrian } else { 53252488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 53354914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 53454914Sbrian log_Printf(LogWARN, "Invalid logout script\n"); 53552488Sbrian } 53636285Sbrian } else 53736285Sbrian datalink_HangupDone(dl); 53836285Sbrian } 53936285Sbrian} 54036285Sbrian 54136285Sbrianstatic void 54236285Sbriandatalink_LayerStart(void *v, struct fsm *fp) 54336285Sbrian{ 54436285Sbrian /* The given FSM is about to start up ! */ 54536285Sbrian struct datalink *dl = (struct datalink *)v; 54636285Sbrian 54736285Sbrian if (fp->proto == PROTO_LCP) 54836285Sbrian (*dl->parent->LayerStart)(dl->parent->object, fp); 54936285Sbrian} 55036285Sbrian 55136285Sbrianstatic void 55236285Sbriandatalink_LayerUp(void *v, struct fsm *fp) 55336285Sbrian{ 55436285Sbrian /* The given fsm is now up */ 55536285Sbrian struct datalink *dl = (struct datalink *)v; 55644106Sbrian struct lcp *lcp = &dl->physical->link.lcp; 55736285Sbrian 55836285Sbrian if (fp->proto == PROTO_LCP) { 55943693Sbrian datalink_GotAuthname(dl, ""); 56044106Sbrian lcp->auth_ineed = lcp->want_auth; 56144106Sbrian lcp->auth_iwait = lcp->his_auth; 56244106Sbrian if (lcp->his_auth || lcp->want_auth) { 56345350Sbrian if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 56436285Sbrian bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 56536285Sbrian log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 56644106Sbrian Auth2Nam(lcp->his_auth, lcp->his_authtype), 56744106Sbrian Auth2Nam(lcp->want_auth, lcp->want_authtype)); 56844106Sbrian if (lcp->his_auth == PROTO_PAP) 56943693Sbrian auth_StartReq(&dl->pap); 57044106Sbrian if (lcp->want_auth == PROTO_CHAP) 57143693Sbrian auth_StartReq(&dl->chap.auth); 57236285Sbrian } else 57336285Sbrian datalink_AuthOk(dl); 57436285Sbrian } 57536285Sbrian} 57636285Sbrian 57744094Sbrianstatic void 57844094Sbriandatalink_AuthReInit(struct datalink *dl) 57944094Sbrian{ 58044094Sbrian auth_StopTimer(&dl->pap); 58144094Sbrian auth_StopTimer(&dl->chap.auth); 58244094Sbrian chap_ReInit(&dl->chap); 58344094Sbrian} 58444094Sbrian 58536285Sbrianvoid 58643693Sbriandatalink_GotAuthname(struct datalink *dl, const char *name) 58736285Sbrian{ 58843693Sbrian strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 58943693Sbrian dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 59036285Sbrian} 59136285Sbrian 59236285Sbrianvoid 59338174Sbriandatalink_NCPUp(struct datalink *dl) 59436285Sbrian{ 59537320Sbrian int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 59636310Sbrian 59736285Sbrian if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 59836285Sbrian /* we've authenticated in multilink mode ! */ 59936285Sbrian switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 60036285Sbrian case MP_LINKSENT: 60136285Sbrian /* We've handed the link off to another ppp (well, we will soon) ! */ 60236285Sbrian return; 60336285Sbrian case MP_UP: 60436285Sbrian /* First link in the bundle */ 60538174Sbrian auth_Select(dl->bundle, dl->peer.authname); 60649434Sbrian bundle_CalculateBandwidth(dl->bundle); 60736285Sbrian /* fall through */ 60836285Sbrian case MP_ADDED: 60936285Sbrian /* We're in multilink mode ! */ 61036310Sbrian dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 61149434Sbrian bundle_CalculateBandwidth(dl->bundle); 61236285Sbrian break; 61336285Sbrian case MP_FAILED: 61436285Sbrian datalink_AuthNotOk(dl); 61536285Sbrian return; 61636285Sbrian } 61736285Sbrian } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 61836285Sbrian log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 61937160Sbrian datalink_NewState(dl, DATALINK_OPEN); 62049434Sbrian bundle_CalculateBandwidth(dl->bundle); 62137160Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 62236285Sbrian return; 62336285Sbrian } else { 62436285Sbrian dl->bundle->ncp.mp.peer = dl->peer; 62536285Sbrian ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 62638174Sbrian auth_Select(dl->bundle, dl->peer.authname); 62736285Sbrian } 62836285Sbrian 62937320Sbrian if (ccpok) { 63037320Sbrian fsm_Up(&dl->physical->link.ccp.fsm); 63137320Sbrian fsm_Open(&dl->physical->link.ccp.fsm); 63237320Sbrian } 63336285Sbrian datalink_NewState(dl, DATALINK_OPEN); 63436285Sbrian bundle_NewPhase(dl->bundle, PHASE_NETWORK); 63536285Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 63636285Sbrian} 63736285Sbrian 63836285Sbrianvoid 63938174Sbriandatalink_CBCPComplete(struct datalink *dl) 64038174Sbrian{ 64138174Sbrian datalink_NewState(dl, DATALINK_LCP); 64244094Sbrian datalink_AuthReInit(dl); 64338174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 64438174Sbrian} 64538174Sbrian 64638174Sbrianvoid 64738174Sbriandatalink_CBCPFailed(struct datalink *dl) 64838174Sbrian{ 64938174Sbrian cbcp_Down(&dl->cbcp); 65038174Sbrian datalink_CBCPComplete(dl); 65138174Sbrian} 65238174Sbrian 65338174Sbrianvoid 65438174Sbriandatalink_AuthOk(struct datalink *dl) 65538174Sbrian{ 65642600Sbrian if ((dl->physical->link.lcp.his_callback.opmask & 65742600Sbrian CALLBACK_BIT(CALLBACK_CBCP) || 65842600Sbrian dl->physical->link.lcp.want_callback.opmask & 65942600Sbrian CALLBACK_BIT(CALLBACK_CBCP)) && 66042600Sbrian !(dl->physical->link.lcp.want_callback.opmask & 66142600Sbrian CALLBACK_BIT(CALLBACK_AUTH))) { 66242600Sbrian /* We must have agreed CBCP if AUTH isn't there any more */ 66338174Sbrian datalink_NewState(dl, DATALINK_CBCP); 66438174Sbrian cbcp_Up(&dl->cbcp); 66538174Sbrian } else if (dl->physical->link.lcp.want_callback.opmask) { 66642600Sbrian /* It's not CBCP */ 66738174Sbrian log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 66838174Sbrian datalink_NewState(dl, DATALINK_LCP); 66944094Sbrian datalink_AuthReInit(dl); 67038174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 67138174Sbrian } else 67238174Sbrian switch (dl->physical->link.lcp.his_callback.opmask) { 67338174Sbrian case 0: 67438174Sbrian datalink_NCPUp(dl); 67538174Sbrian break; 67638174Sbrian 67738174Sbrian case CALLBACK_BIT(CALLBACK_AUTH): 67838174Sbrian auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 67938174Sbrian sizeof dl->cbcp.fsm.phone); 68038174Sbrian if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 68138174Sbrian log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 68238174Sbrian dl->peer.authname); 68338174Sbrian *dl->cbcp.fsm.phone = '\0'; 68438174Sbrian } else { 68538174Sbrian char *ptr = strchr(dl->cbcp.fsm.phone, ','); 68638174Sbrian if (ptr) 68738174Sbrian *ptr = '\0'; /* Call back on the first number */ 68838174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 68938174Sbrian dl->cbcp.fsm.phone); 69038174Sbrian dl->cbcp.required = 1; 69138174Sbrian } 69238174Sbrian dl->cbcp.fsm.delay = 0; 69338174Sbrian datalink_NewState(dl, DATALINK_LCP); 69444094Sbrian datalink_AuthReInit(dl); 69538174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 69638174Sbrian break; 69738174Sbrian 69838174Sbrian case CALLBACK_BIT(CALLBACK_E164): 69938174Sbrian strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 70038174Sbrian sizeof dl->cbcp.fsm.phone - 1); 70138174Sbrian dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 70238174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 70338174Sbrian dl->cbcp.fsm.phone); 70438174Sbrian dl->cbcp.required = 1; 70538174Sbrian dl->cbcp.fsm.delay = 0; 70638174Sbrian datalink_NewState(dl, DATALINK_LCP); 70744094Sbrian datalink_AuthReInit(dl); 70838174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 70938174Sbrian break; 71038174Sbrian 71138174Sbrian default: 71238174Sbrian log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 71338174Sbrian dl->name); 71438174Sbrian datalink_NewState(dl, DATALINK_LCP); 71544094Sbrian datalink_AuthReInit(dl); 71638174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 71738174Sbrian break; 71838174Sbrian } 71938174Sbrian} 72038174Sbrian 72138174Sbrianvoid 72236285Sbriandatalink_AuthNotOk(struct datalink *dl) 72336285Sbrian{ 72436285Sbrian datalink_NewState(dl, DATALINK_LCP); 72544094Sbrian datalink_AuthReInit(dl); 72636285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 72736285Sbrian} 72836285Sbrian 72936285Sbrianstatic void 73036285Sbriandatalink_LayerDown(void *v, struct fsm *fp) 73136285Sbrian{ 73236285Sbrian /* The given FSM has been told to come down */ 73336285Sbrian struct datalink *dl = (struct datalink *)v; 73436285Sbrian 73536285Sbrian if (fp->proto == PROTO_LCP) { 73636285Sbrian switch (dl->state) { 73736285Sbrian case DATALINK_OPEN: 73836285Sbrian peerid_Init(&dl->peer); 73937060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 74036928Sbrian datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 74136285Sbrian (*dl->parent->LayerDown)(dl->parent->object, fp); 74238174Sbrian /* fall through (just in case) */ 74336285Sbrian 74438174Sbrian case DATALINK_CBCP: 74538174Sbrian if (!dl->cbcp.required) 74638174Sbrian cbcp_Down(&dl->cbcp); 74738174Sbrian /* fall through (just in case) */ 74838174Sbrian 74936285Sbrian case DATALINK_AUTH: 75036285Sbrian timer_Stop(&dl->pap.authtimer); 75136285Sbrian timer_Stop(&dl->chap.auth.authtimer); 75236285Sbrian } 75336285Sbrian datalink_NewState(dl, DATALINK_LCP); 75444094Sbrian datalink_AuthReInit(dl); 75536285Sbrian } 75636285Sbrian} 75736285Sbrian 75836285Sbrianstatic void 75936285Sbriandatalink_LayerFinish(void *v, struct fsm *fp) 76036285Sbrian{ 76136285Sbrian /* The given fsm is now down */ 76236285Sbrian struct datalink *dl = (struct datalink *)v; 76336285Sbrian 76436285Sbrian if (fp->proto == PROTO_LCP) { 76537060Sbrian fsm2initial(fp); 76636285Sbrian (*dl->parent->LayerFinish)(dl->parent->object, fp); 76737007Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 76836285Sbrian } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 76936285Sbrian fsm_Open(fp); /* CCP goes to ST_STOPPED */ 77036285Sbrian} 77136285Sbrian 77236285Sbrianstruct datalink * 77336285Sbriandatalink_Create(const char *name, struct bundle *bundle, int type) 77436285Sbrian{ 77536285Sbrian struct datalink *dl; 77636285Sbrian 77736285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 77836285Sbrian if (dl == NULL) 77936285Sbrian return dl; 78036285Sbrian 78136285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 78236285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 78336285Sbrian dl->desc.IsSet = datalink_IsSet; 78436285Sbrian dl->desc.Read = datalink_Read; 78536285Sbrian dl->desc.Write = datalink_Write; 78636285Sbrian 78736285Sbrian dl->state = DATALINK_CLOSED; 78836285Sbrian 78936285Sbrian *dl->cfg.script.dial = '\0'; 79036285Sbrian *dl->cfg.script.login = '\0'; 79152488Sbrian *dl->cfg.script.logout = '\0'; 79236285Sbrian *dl->cfg.script.hangup = '\0'; 79336285Sbrian *dl->cfg.phone.list = '\0'; 79436285Sbrian *dl->phone.list = '\0'; 79536285Sbrian dl->phone.next = NULL; 79636285Sbrian dl->phone.alt = NULL; 79736285Sbrian dl->phone.chosen = "N/A"; 79837007Sbrian dl->stayonline = 0; 79936285Sbrian dl->script.run = 1; 80036285Sbrian dl->script.packetmode = 1; 80136285Sbrian mp_linkInit(&dl->mp); 80236285Sbrian 80336285Sbrian dl->bundle = bundle; 80436285Sbrian dl->next = NULL; 80536285Sbrian 80644468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 80736285Sbrian 80844468Sbrian dl->dial.tries = 0; 80936285Sbrian dl->cfg.dial.max = 1; 81036285Sbrian dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 81136285Sbrian dl->cfg.dial.timeout = DIAL_TIMEOUT; 81244468Sbrian dl->cfg.dial.inc = 0; 81344468Sbrian dl->cfg.dial.maxinc = 10; 81436285Sbrian 81536285Sbrian dl->reconnect_tries = 0; 81636285Sbrian dl->cfg.reconnect.max = 0; 81736285Sbrian dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 81836285Sbrian 81938174Sbrian dl->cfg.callback.opmask = 0; 82038174Sbrian dl->cfg.cbcp.delay = 0; 82138174Sbrian *dl->cfg.cbcp.phone = '\0'; 82238174Sbrian dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 82338174Sbrian 82436285Sbrian dl->name = strdup(name); 82536285Sbrian peerid_Init(&dl->peer); 82636285Sbrian dl->parent = &bundle->fsm; 82736285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 82836285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 82936285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 83036285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 83136285Sbrian dl->fsmp.object = dl; 83236285Sbrian 83346686Sbrian if ((dl->physical = physical_Create(dl, type)) == NULL) { 83436285Sbrian free(dl->name); 83536285Sbrian free(dl); 83636285Sbrian return NULL; 83736285Sbrian } 83843693Sbrian 83943693Sbrian pap_Init(&dl->pap, dl->physical); 84043693Sbrian chap_Init(&dl->chap, dl->physical); 84138174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 84236285Sbrian 84352488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 84454055Sbrian chat_Init(&dl->chat, dl->physical); 84552488Sbrian 84636285Sbrian log_Printf(LogPHASE, "%s: Created in %s state\n", 84736285Sbrian dl->name, datalink_State(dl)); 84836285Sbrian 84936285Sbrian return dl; 85036285Sbrian} 85136285Sbrian 85236285Sbrianstruct datalink * 85336285Sbriandatalink_Clone(struct datalink *odl, const char *name) 85436285Sbrian{ 85536285Sbrian struct datalink *dl; 85636285Sbrian 85736285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 85836285Sbrian if (dl == NULL) 85936285Sbrian return dl; 86036285Sbrian 86136285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 86236285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 86336285Sbrian dl->desc.IsSet = datalink_IsSet; 86436285Sbrian dl->desc.Read = datalink_Read; 86536285Sbrian dl->desc.Write = datalink_Write; 86636285Sbrian 86736285Sbrian dl->state = DATALINK_CLOSED; 86836285Sbrian 86936285Sbrian memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 87036285Sbrian mp_linkInit(&dl->mp); 87136285Sbrian *dl->phone.list = '\0'; 87236285Sbrian dl->phone.next = NULL; 87336285Sbrian dl->phone.alt = NULL; 87436285Sbrian dl->phone.chosen = "N/A"; 87536285Sbrian dl->bundle = odl->bundle; 87636285Sbrian dl->next = NULL; 87744468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 87844468Sbrian dl->dial.tries = 0; 87936285Sbrian dl->reconnect_tries = 0; 88036285Sbrian dl->name = strdup(name); 88136285Sbrian peerid_Init(&dl->peer); 88236285Sbrian dl->parent = odl->parent; 88336285Sbrian memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 88436285Sbrian dl->fsmp.object = dl; 88536285Sbrian 88646686Sbrian if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { 88736285Sbrian free(dl->name); 88836285Sbrian free(dl); 88936285Sbrian return NULL; 89036285Sbrian } 89143693Sbrian pap_Init(&dl->pap, dl->physical); 89244305Sbrian dl->pap.cfg = odl->pap.cfg; 89343693Sbrian 89443693Sbrian chap_Init(&dl->chap, dl->physical); 89544305Sbrian dl->chap.auth.cfg = odl->chap.auth.cfg; 89643693Sbrian 89736285Sbrian memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 89836285Sbrian memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 89936285Sbrian sizeof dl->physical->link.lcp.cfg); 90036285Sbrian memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 90136285Sbrian sizeof dl->physical->link.ccp.cfg); 90236285Sbrian memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 90336285Sbrian sizeof dl->physical->async.cfg); 90436285Sbrian 90538174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 90636285Sbrian 90752488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 90854055Sbrian chat_Init(&dl->chat, dl->physical); 90952488Sbrian 91036285Sbrian log_Printf(LogPHASE, "%s: Cloned in %s state\n", 91136285Sbrian dl->name, datalink_State(dl)); 91236285Sbrian 91336285Sbrian return dl; 91436285Sbrian} 91536285Sbrian 91636285Sbrianstruct datalink * 91736285Sbriandatalink_Destroy(struct datalink *dl) 91836285Sbrian{ 91936285Sbrian struct datalink *result; 92036285Sbrian 92136285Sbrian if (dl->state != DATALINK_CLOSED) { 92236285Sbrian log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 92336285Sbrian datalink_State(dl)); 92436285Sbrian switch (dl->state) { 92536285Sbrian case DATALINK_HANGUP: 92636285Sbrian case DATALINK_DIAL: 92736285Sbrian case DATALINK_LOGIN: 92854055Sbrian chat_Finish(&dl->chat); /* Gotta blat the timers ! */ 92936285Sbrian break; 93036285Sbrian } 93136285Sbrian } 93236285Sbrian 93354055Sbrian chat_Destroy(&dl->chat); 93444468Sbrian timer_Stop(&dl->dial.timer); 93536285Sbrian result = dl->next; 93646686Sbrian physical_Destroy(dl->physical); 93736285Sbrian free(dl->name); 93836285Sbrian free(dl); 93936285Sbrian 94036285Sbrian return result; 94136285Sbrian} 94236285Sbrian 94336285Sbrianvoid 94436285Sbriandatalink_Up(struct datalink *dl, int runscripts, int packetmode) 94536285Sbrian{ 94636285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 94736285Sbrian /* Ignore scripts */ 94836285Sbrian runscripts = 0; 94936285Sbrian 95036285Sbrian switch (dl->state) { 95136285Sbrian case DATALINK_CLOSED: 95236285Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 95336285Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 95436285Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 95536285Sbrian datalink_NewState(dl, DATALINK_OPENING); 95636285Sbrian dl->reconnect_tries = 95736285Sbrian dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 95844468Sbrian dl->dial.tries = dl->cfg.dial.max; 95936285Sbrian dl->script.run = runscripts; 96036285Sbrian dl->script.packetmode = packetmode; 96136285Sbrian break; 96236285Sbrian 96336285Sbrian case DATALINK_OPENING: 96436285Sbrian if (!dl->script.run && runscripts) 96536285Sbrian dl->script.run = 1; 96636285Sbrian /* fall through */ 96736285Sbrian 96836285Sbrian case DATALINK_DIAL: 96936285Sbrian case DATALINK_LOGIN: 97036285Sbrian case DATALINK_READY: 97136285Sbrian if (!dl->script.packetmode && packetmode) { 97236285Sbrian dl->script.packetmode = 1; 97360945Sbrian if (dl->state == DATALINK_READY) { 97460945Sbrian dl->script.run = 0; 97560945Sbrian datalink_NewState(dl, DATALINK_CARRIER); 97660945Sbrian } 97736285Sbrian } 97836285Sbrian break; 97936285Sbrian } 98036285Sbrian} 98136285Sbrian 98236285Sbrianvoid 98337007Sbriandatalink_Close(struct datalink *dl, int how) 98436285Sbrian{ 98536285Sbrian /* Please close */ 98636285Sbrian switch (dl->state) { 98736285Sbrian case DATALINK_OPEN: 98836285Sbrian peerid_Init(&dl->peer); 98937060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 99036285Sbrian /* fall through */ 99136285Sbrian 99238174Sbrian case DATALINK_CBCP: 99336285Sbrian case DATALINK_AUTH: 99436285Sbrian case DATALINK_LCP: 99544094Sbrian datalink_AuthReInit(dl); 99636285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 99737007Sbrian if (how != CLOSE_NORMAL) { 99844468Sbrian dl->dial.tries = -1; 99936285Sbrian dl->reconnect_tries = 0; 100037007Sbrian if (how == CLOSE_LCP) 100137007Sbrian dl->stayonline = 1; 100236285Sbrian } 100352029Sbrian break; 100436285Sbrian 100536285Sbrian default: 100637007Sbrian datalink_ComeDown(dl, how); 100736285Sbrian } 100836285Sbrian} 100936285Sbrian 101036285Sbrianvoid 101137007Sbriandatalink_Down(struct datalink *dl, int how) 101236285Sbrian{ 101336285Sbrian /* Carrier is lost */ 101436285Sbrian switch (dl->state) { 101536285Sbrian case DATALINK_OPEN: 101636285Sbrian peerid_Init(&dl->peer); 101737060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 101836285Sbrian /* fall through */ 101936285Sbrian 102038174Sbrian case DATALINK_CBCP: 102136285Sbrian case DATALINK_AUTH: 102236285Sbrian case DATALINK_LCP: 102337060Sbrian fsm2initial(&dl->physical->link.lcp.fsm); 102456656Sbrian if (dl->state == DATALINK_OPENING) 102556656Sbrian return; /* we're doing a callback... */ 102636285Sbrian /* fall through */ 102736285Sbrian 102836285Sbrian default: 102937007Sbrian datalink_ComeDown(dl, how); 103036285Sbrian } 103136285Sbrian} 103236285Sbrian 103336285Sbrianvoid 103436285Sbriandatalink_StayDown(struct datalink *dl) 103536285Sbrian{ 103636285Sbrian dl->reconnect_tries = 0; 103736285Sbrian} 103836285Sbrian 103937007Sbrianvoid 104037007Sbriandatalink_DontHangup(struct datalink *dl) 104137007Sbrian{ 104237012Sbrian if (dl->state >= DATALINK_LCP) 104337012Sbrian dl->stayonline = 1; 104437007Sbrian} 104537007Sbrian 104636285Sbrianint 104736285Sbriandatalink_Show(struct cmdargs const *arg) 104836285Sbrian{ 104936285Sbrian prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 105038174Sbrian prompt_Printf(arg->prompt, " State: %s\n", 105136285Sbrian datalink_State(arg->cx)); 105238174Sbrian prompt_Printf(arg->prompt, " Peer name: "); 105336285Sbrian if (*arg->cx->peer.authname) 105436285Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 105536285Sbrian else if (arg->cx->state == DATALINK_OPEN) 105636285Sbrian prompt_Printf(arg->prompt, "None requested\n"); 105736285Sbrian else 105836285Sbrian prompt_Printf(arg->prompt, "N/A\n"); 105938174Sbrian prompt_Printf(arg->prompt, " Discriminator: %s\n", 106036285Sbrian mp_Enddisc(arg->cx->peer.enddisc.class, 106136285Sbrian arg->cx->peer.enddisc.address, 106236285Sbrian arg->cx->peer.enddisc.len)); 106336285Sbrian 106436285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 106538174Sbrian prompt_Printf(arg->prompt, " Phone List: %s\n", 106636285Sbrian arg->cx->cfg.phone.list); 106736285Sbrian if (arg->cx->cfg.dial.max) 106838174Sbrian prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 106936285Sbrian arg->cx->cfg.dial.max); 107036285Sbrian else 107138174Sbrian prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 107244261Sbrian if (arg->cx->cfg.dial.next_timeout >= 0) 107336285Sbrian prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 107436285Sbrian else 107536285Sbrian prompt_Printf(arg->prompt, "random/"); 107644261Sbrian if (arg->cx->cfg.dial.timeout >= 0) 107736285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 107836285Sbrian else 107936285Sbrian prompt_Printf(arg->prompt, "random\n"); 108038174Sbrian prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 108136285Sbrian arg->cx->cfg.reconnect.max); 108236285Sbrian if (arg->cx->cfg.reconnect.timeout > 0) 108336285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 108436285Sbrian else 108536285Sbrian prompt_Printf(arg->prompt, "random\n"); 108638174Sbrian prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 108738174Sbrian PHYS_DIRECT ? "accepted: " : "requested:"); 108838174Sbrian if (!arg->cx->cfg.callback.opmask) 108938174Sbrian prompt_Printf(arg->prompt, "none\n"); 109038174Sbrian else { 109138174Sbrian int comma = 0; 109238174Sbrian 109338174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 109438174Sbrian prompt_Printf(arg->prompt, "none"); 109538174Sbrian comma = 1; 109638174Sbrian } 109738174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 109838174Sbrian prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 109938174Sbrian comma = 1; 110038174Sbrian } 110138174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 110238174Sbrian prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 110338174Sbrian if (arg->cx->physical->type != PHYS_DIRECT) 110438174Sbrian prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 110538174Sbrian comma = 1; 110638174Sbrian } 110738174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 110838174Sbrian prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 110938174Sbrian prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 111038174Sbrian arg->cx->cfg.cbcp.delay); 111140483Sbrian prompt_Printf(arg->prompt, " phone: "); 111240483Sbrian if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 111340483Sbrian if (arg->cx->physical->type & PHYS_DIRECT) 111440483Sbrian prompt_Printf(arg->prompt, "Caller decides\n"); 111540483Sbrian else 111640483Sbrian prompt_Printf(arg->prompt, "Dialback server decides\n"); 111740483Sbrian } else 111840483Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 111938174Sbrian prompt_Printf(arg->prompt, " timeout: %lds\n", 112038174Sbrian arg->cx->cfg.cbcp.fsmretry); 112138174Sbrian } else 112238174Sbrian prompt_Printf(arg->prompt, "\n"); 112338174Sbrian } 112438174Sbrian 112538174Sbrian prompt_Printf(arg->prompt, " Dial Script: %s\n", 112636285Sbrian arg->cx->cfg.script.dial); 112738174Sbrian prompt_Printf(arg->prompt, " Login Script: %s\n", 112836285Sbrian arg->cx->cfg.script.login); 112952488Sbrian prompt_Printf(arg->prompt, " Logout Script: %s\n", 113052488Sbrian arg->cx->cfg.script.logout); 113138174Sbrian prompt_Printf(arg->prompt, " Hangup Script: %s\n", 113236285Sbrian arg->cx->cfg.script.hangup); 113336285Sbrian return 0; 113436285Sbrian} 113536285Sbrian 113636285Sbrianint 113736285Sbriandatalink_SetReconnect(struct cmdargs const *arg) 113836285Sbrian{ 113936285Sbrian if (arg->argc == arg->argn+2) { 114036285Sbrian arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 114136285Sbrian arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 114236285Sbrian return 0; 114336285Sbrian } 114436285Sbrian return -1; 114536285Sbrian} 114636285Sbrian 114736285Sbrianint 114836285Sbriandatalink_SetRedial(struct cmdargs const *arg) 114936285Sbrian{ 115044468Sbrian const char *sep, *osep; 115144468Sbrian int timeout, inc, maxinc, tries; 115236285Sbrian 115336285Sbrian if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 115436285Sbrian if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 115536285Sbrian (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 115636285Sbrian arg->cx->cfg.dial.timeout = -1; 115736285Sbrian randinit(); 115836285Sbrian } else { 115936285Sbrian timeout = atoi(arg->argv[arg->argn]); 116036285Sbrian 116136285Sbrian if (timeout >= 0) 116236285Sbrian arg->cx->cfg.dial.timeout = timeout; 116336285Sbrian else { 116436285Sbrian log_Printf(LogWARN, "Invalid redial timeout\n"); 116536285Sbrian return -1; 116636285Sbrian } 116736285Sbrian } 116836285Sbrian 116944468Sbrian sep = strchr(arg->argv[arg->argn], '+'); 117044468Sbrian if (sep) { 117144468Sbrian inc = atoi(++sep); 117244468Sbrian osep = sep; 117344468Sbrian if (inc >= 0) 117444468Sbrian arg->cx->cfg.dial.inc = inc; 117544468Sbrian else { 117644468Sbrian log_Printf(LogWARN, "Invalid timeout increment\n"); 117744468Sbrian return -1; 117844468Sbrian } 117944468Sbrian sep = strchr(sep, '-'); 118044468Sbrian if (sep) { 118144468Sbrian maxinc = atoi(++sep); 118244468Sbrian if (maxinc >= 0) 118344468Sbrian arg->cx->cfg.dial.maxinc = maxinc; 118444468Sbrian else { 118544468Sbrian log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 118644468Sbrian return -1; 118744468Sbrian } 118844468Sbrian } else { 118944468Sbrian /* Default timeout increment */ 119044468Sbrian arg->cx->cfg.dial.maxinc = 10; 119144468Sbrian sep = osep; 119244468Sbrian } 119344468Sbrian } else { 119444468Sbrian /* Default timeout increment & max increment */ 119544468Sbrian arg->cx->cfg.dial.inc = 0; 119644468Sbrian arg->cx->cfg.dial.maxinc = 10; 119744468Sbrian sep = arg->argv[arg->argn]; 119844468Sbrian } 119944468Sbrian 120044468Sbrian sep = strchr(sep, '.'); 120144468Sbrian if (sep) { 120244468Sbrian if (strcasecmp(++sep, "random") == 0) { 120336285Sbrian arg->cx->cfg.dial.next_timeout = -1; 120436285Sbrian randinit(); 120536285Sbrian } else { 120644468Sbrian timeout = atoi(sep); 120736285Sbrian if (timeout >= 0) 120836285Sbrian arg->cx->cfg.dial.next_timeout = timeout; 120936285Sbrian else { 121036285Sbrian log_Printf(LogWARN, "Invalid next redial timeout\n"); 121136285Sbrian return -1; 121236285Sbrian } 121336285Sbrian } 121436285Sbrian } else 121536285Sbrian /* Default next timeout */ 121636285Sbrian arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 121736285Sbrian 121836285Sbrian if (arg->argc == arg->argn+2) { 121936285Sbrian tries = atoi(arg->argv[arg->argn+1]); 122036285Sbrian 122136285Sbrian if (tries >= 0) { 122236285Sbrian arg->cx->cfg.dial.max = tries; 122336285Sbrian } else { 122436285Sbrian log_Printf(LogWARN, "Invalid retry value\n"); 122536285Sbrian return 1; 122636285Sbrian } 122736285Sbrian } 122836285Sbrian return 0; 122936285Sbrian } 123044468Sbrian 123136285Sbrian return -1; 123236285Sbrian} 123336285Sbrian 123455146Sbrianstatic const char * const states[] = { 123536285Sbrian "closed", 123636285Sbrian "opening", 123736285Sbrian "hangup", 123836285Sbrian "dial", 123949472Sbrian "carrier", 124052488Sbrian "logout", 124136285Sbrian "login", 124236285Sbrian "ready", 124336285Sbrian "lcp", 124436285Sbrian "auth", 124538174Sbrian "cbcp", 124636285Sbrian "open" 124736285Sbrian}; 124836285Sbrian 124936285Sbrianconst char * 125036285Sbriandatalink_State(struct datalink *dl) 125136285Sbrian{ 125236285Sbrian if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 125336285Sbrian return "unknown"; 125436285Sbrian return states[dl->state]; 125536285Sbrian} 125636285Sbrian 125736285Sbrianstatic void 125836285Sbriandatalink_NewState(struct datalink *dl, int state) 125936285Sbrian{ 126036285Sbrian if (state != dl->state) { 126136285Sbrian if (state >= 0 && state < sizeof states / sizeof states[0]) { 126236285Sbrian log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 126336285Sbrian states[state]); 126436285Sbrian dl->state = state; 126536285Sbrian } else 126636285Sbrian log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 126736285Sbrian } 126836285Sbrian} 126936285Sbrian 127036285Sbrianstruct datalink * 127136285Sbrianiov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 127252942Sbrian int fd, int *auxfd, int *nauxfd) 127336285Sbrian{ 127436285Sbrian struct datalink *dl, *cdl; 127544305Sbrian struct fsm_retry copy; 127636285Sbrian char *oname; 127736285Sbrian 127836285Sbrian dl = (struct datalink *)iov[(*niov)++].iov_base; 127936285Sbrian dl->name = iov[*niov].iov_base; 128036285Sbrian 128136285Sbrian if (dl->name[DATALINK_MAXNAME-1]) { 128236285Sbrian dl->name[DATALINK_MAXNAME-1] = '\0'; 128336285Sbrian if (strlen(dl->name) == DATALINK_MAXNAME - 1) 128436285Sbrian log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 128536285Sbrian } 128636285Sbrian 128736285Sbrian /* Make sure the name is unique ! */ 128836285Sbrian oname = NULL; 128936285Sbrian do { 129036285Sbrian for (cdl = bundle->links; cdl; cdl = cdl->next) 129136285Sbrian if (!strcasecmp(dl->name, cdl->name)) { 129236285Sbrian if (oname) 129336285Sbrian free(datalink_NextName(dl)); 129436285Sbrian else 129536285Sbrian oname = datalink_NextName(dl); 129636285Sbrian break; /* Keep renaming 'till we have no conflicts */ 129736285Sbrian } 129836285Sbrian } while (cdl); 129936285Sbrian 130036285Sbrian if (oname) { 130136285Sbrian log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 130236285Sbrian free(oname); 130336285Sbrian } else { 130436285Sbrian dl->name = strdup(dl->name); 130536285Sbrian free(iov[*niov].iov_base); 130636285Sbrian } 130736285Sbrian (*niov)++; 130836285Sbrian 130936285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 131036285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 131136285Sbrian dl->desc.IsSet = datalink_IsSet; 131236285Sbrian dl->desc.Read = datalink_Read; 131336285Sbrian dl->desc.Write = datalink_Write; 131436285Sbrian 131536285Sbrian mp_linkInit(&dl->mp); 131636285Sbrian *dl->phone.list = '\0'; 131736285Sbrian dl->phone.next = NULL; 131836285Sbrian dl->phone.alt = NULL; 131936285Sbrian dl->phone.chosen = "N/A"; 132036285Sbrian 132136285Sbrian dl->bundle = bundle; 132236285Sbrian dl->next = NULL; 132344468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 132444468Sbrian dl->dial.tries = 0; 132536285Sbrian dl->reconnect_tries = 0; 132636285Sbrian dl->parent = &bundle->fsm; 132736285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 132836285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 132936285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 133036285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 133136285Sbrian dl->fsmp.object = dl; 133236285Sbrian 133352942Sbrian dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); 133436285Sbrian 133536285Sbrian if (!dl->physical) { 133636285Sbrian free(dl->name); 133736285Sbrian free(dl); 133836285Sbrian dl = NULL; 133936285Sbrian } else { 134044305Sbrian copy = dl->pap.cfg.fsm; 134143693Sbrian pap_Init(&dl->pap, dl->physical); 134244305Sbrian dl->pap.cfg.fsm = copy; 134343693Sbrian 134444305Sbrian copy = dl->chap.auth.cfg.fsm; 134543693Sbrian chap_Init(&dl->chap, dl->physical); 134644305Sbrian dl->chap.auth.cfg.fsm = copy; 134743693Sbrian 134838174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 134936285Sbrian 135052488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 135154055Sbrian chat_Init(&dl->chat, dl->physical); 135252488Sbrian 135336285Sbrian log_Printf(LogPHASE, "%s: Transferred in %s state\n", 135436285Sbrian dl->name, datalink_State(dl)); 135536285Sbrian } 135636285Sbrian 135736285Sbrian return dl; 135836285Sbrian} 135936285Sbrian 136036285Sbrianint 136136450Sbriandatalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 136253684Sbrian int *auxfd, int *nauxfd) 136336285Sbrian{ 136436285Sbrian /* If `dl' is NULL, we're allocating before a Fromiov() */ 136536285Sbrian int link_fd; 136636285Sbrian 136736285Sbrian if (dl) { 136844468Sbrian timer_Stop(&dl->dial.timer); 136938174Sbrian /* The following is purely for the sake of paranoia */ 137038174Sbrian cbcp_Down(&dl->cbcp); 137136285Sbrian timer_Stop(&dl->pap.authtimer); 137236285Sbrian timer_Stop(&dl->chap.auth.authtimer); 137336285Sbrian } 137436285Sbrian 137536285Sbrian if (*niov >= maxiov - 1) { 137636285Sbrian log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 137736285Sbrian if (dl) { 137836285Sbrian free(dl->name); 137936285Sbrian free(dl); 138036285Sbrian } 138136285Sbrian return -1; 138236285Sbrian } 138336285Sbrian 138453684Sbrian iov[*niov].iov_base = (void *)dl; 138536285Sbrian iov[(*niov)++].iov_len = sizeof *dl; 138653684Sbrian iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL; 138736285Sbrian iov[(*niov)++].iov_len = DATALINK_MAXNAME; 138836285Sbrian 138952942Sbrian link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, 139053684Sbrian nauxfd); 139136285Sbrian 139236285Sbrian if (link_fd == -1 && dl) { 139336285Sbrian free(dl->name); 139436285Sbrian free(dl); 139536285Sbrian } 139636285Sbrian 139736285Sbrian return link_fd; 139836285Sbrian} 139936285Sbrian 140036285Sbrianvoid 140136285Sbriandatalink_Rename(struct datalink *dl, const char *name) 140236285Sbrian{ 140336285Sbrian free(dl->name); 140436285Sbrian dl->physical->link.name = dl->name = strdup(name); 140536285Sbrian} 140636285Sbrian 140736285Sbrianchar * 140836285Sbriandatalink_NextName(struct datalink *dl) 140936285Sbrian{ 141036285Sbrian int f, n; 141136285Sbrian char *name, *oname; 141236285Sbrian 141336285Sbrian n = strlen(dl->name); 141436285Sbrian name = (char *)malloc(n+3); 141536285Sbrian for (f = n - 1; f >= 0; f--) 141636285Sbrian if (!isdigit(dl->name[f])) 141736285Sbrian break; 141836285Sbrian n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 141936285Sbrian sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 142036285Sbrian oname = dl->name; 142136345Sbrian dl->name = name; 142236345Sbrian /* our physical link name isn't updated (it probably isn't created yet) */ 142336285Sbrian return oname; 142436285Sbrian} 142536285Sbrian 142636285Sbrianint 142736285Sbriandatalink_SetMode(struct datalink *dl, int mode) 142836285Sbrian{ 142936285Sbrian if (!physical_SetMode(dl->physical, mode)) 143036285Sbrian return 0; 143136285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 143236285Sbrian dl->script.run = 0; 143336285Sbrian if (dl->physical->type == PHYS_DIRECT) 143436285Sbrian dl->reconnect_tries = 0; 143553830Sbrian if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) && 143653830Sbrian dl->state <= DATALINK_READY) 143736285Sbrian datalink_Up(dl, 1, 1); 143836285Sbrian return 1; 143936285Sbrian} 144044468Sbrian 144144468Sbrianint 144244468Sbriandatalink_GetDialTimeout(struct datalink *dl) 144344468Sbrian{ 144444468Sbrian int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 144544468Sbrian 144644468Sbrian if (dl->dial.incs < dl->cfg.dial.maxinc) 144744468Sbrian dl->dial.incs++; 144844468Sbrian 144944468Sbrian return result; 145044468Sbrian} 1451