datalink.c revision 53830
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 53830 1999-11-28 15:50:08Z 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 "lcp.h" 4936285Sbrian#include "descriptor.h" 5036285Sbrian#include "lqr.h" 5136285Sbrian#include "hdlc.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) 8636285Sbrian log_Printf(LogPHASE, "%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 12352488Sbrian chat_Destroy(&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); 16036285Sbrian if (!dl->bundle->CleaningUp) 16144468Sbrian datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 16236285Sbrian } else { 16336285Sbrian datalink_NewState(dl, DATALINK_OPENING); 16452412Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 16552412Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 16645385Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 16744468Sbrian if (dl->dial.tries < 0) { 16836285Sbrian datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 16944468Sbrian dl->dial.tries = dl->cfg.dial.max; 17044468Sbrian dl->dial.incs = 0; 17136285Sbrian dl->reconnect_tries--; 17236285Sbrian } else { 17336285Sbrian if (dl->phone.next == NULL) 17444468Sbrian datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 17536285Sbrian else 17636285Sbrian datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 17736285Sbrian } 17836285Sbrian } 17936285Sbrian} 18036285Sbrian 18149472Sbrianconst char * 18236285Sbriandatalink_ChoosePhoneNumber(struct datalink *dl) 18336285Sbrian{ 18436285Sbrian char *phone; 18536285Sbrian 18636285Sbrian if (dl->phone.alt == NULL) { 18736285Sbrian if (dl->phone.next == NULL) { 18836285Sbrian strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 18936285Sbrian dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 19048003Sbrian if (*dl->phone.list == '\0') 19148003Sbrian return ""; 19236285Sbrian dl->phone.next = dl->phone.list; 19336285Sbrian } 19436285Sbrian dl->phone.alt = strsep(&dl->phone.next, ":"); 19536285Sbrian } 19636285Sbrian phone = strsep(&dl->phone.alt, "|"); 19736285Sbrian dl->phone.chosen = *phone ? phone : "[NONE]"; 19836285Sbrian if (*phone) 19936285Sbrian log_Printf(LogPHASE, "Phone: %s\n", phone); 20036285Sbrian return phone; 20136285Sbrian} 20236285Sbrian 20336285Sbrianstatic void 20436285Sbriandatalink_LoginDone(struct datalink *dl) 20536285Sbrian{ 20652488Sbrian chat_Destroy(&dl->chat); 20752488Sbrian 20836285Sbrian if (!dl->script.packetmode) { 20944468Sbrian dl->dial.tries = -1; 21044468Sbrian dl->dial.incs = 0; 21136285Sbrian datalink_NewState(dl, DATALINK_READY); 21246686Sbrian } else if (!physical_Raw(dl->physical)) { 21344468Sbrian dl->dial.tries = 0; 21436285Sbrian log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 21536285Sbrian if (dl->script.run) { 21652488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 21752488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.logout, NULL); 21836285Sbrian } else { 21947061Sbrian physical_StopDeviceTimer(dl->physical); 22036285Sbrian if (dl->physical->type == PHYS_DEDICATED) 22136285Sbrian /* force a redial timeout */ 22246686Sbrian physical_Close(dl->physical); 22336285Sbrian datalink_HangupDone(dl); 22436285Sbrian } 22536285Sbrian } else { 22644468Sbrian dl->dial.tries = -1; 22744468Sbrian dl->dial.incs = 0; 22836285Sbrian 22936285Sbrian hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 23036285Sbrian async_Init(&dl->physical->async); 23136285Sbrian 23236285Sbrian lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 23336285Sbrian 0 : dl->physical->link.lcp.cfg.openmode); 23436285Sbrian ccp_Setup(&dl->physical->link.ccp); 23536285Sbrian 23636285Sbrian datalink_NewState(dl, DATALINK_LCP); 23736285Sbrian fsm_Up(&dl->physical->link.lcp.fsm); 23836285Sbrian fsm_Open(&dl->physical->link.lcp.fsm); 23936285Sbrian } 24036285Sbrian} 24136285Sbrian 24236285Sbrianstatic int 24336285Sbriandatalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 24436285Sbrian int *n) 24536285Sbrian{ 24636285Sbrian struct datalink *dl = descriptor2datalink(d); 24736285Sbrian int result; 24836285Sbrian 24936285Sbrian result = 0; 25036285Sbrian switch (dl->state) { 25136285Sbrian case DATALINK_CLOSED: 25253830Sbrian if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND| 25353830Sbrian PHYS_FOREGROUND|PHYS_DDIAL)) && 25447863Sbrian !dl->bundle->CleaningUp) 25536285Sbrian /* 25636465Sbrian * Our first time in - DEDICATED & DDIAL never come down, and 25753830Sbrian * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter 25853830Sbrian * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up() 25953830Sbrian * and fall through. 26036285Sbrian */ 26136285Sbrian datalink_Up(dl, 1, 1); 26236285Sbrian else 26336285Sbrian break; 26436285Sbrian /* fall through */ 26536285Sbrian 26636285Sbrian case DATALINK_OPENING: 26744468Sbrian if (dl->dial.timer.state != TIMER_RUNNING) { 26844468Sbrian if (--dl->dial.tries < 0) 26944468Sbrian dl->dial.tries = 0; 27046686Sbrian if (physical_Open(dl->physical, dl->bundle) >= 0) { 27138200Sbrian log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 27238200Sbrian "Type `~?' for help\r\n", dl->name, 27338200Sbrian dl->physical->name.full); 27436285Sbrian if (dl->script.run) { 27536285Sbrian datalink_NewState(dl, DATALINK_DIAL); 27652488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 27749472Sbrian *dl->cfg.script.dial ? 27849472Sbrian datalink_ChoosePhoneNumber(dl) : ""); 27936465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 28036285Sbrian dl->cfg.dial.max) 28136285Sbrian log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 28244468Sbrian dl->name, dl->cfg.dial.max - dl->dial.tries, 28336285Sbrian dl->cfg.dial.max); 28436285Sbrian } else 28551978Sbrian datalink_NewState(dl, DATALINK_CARRIER); 28641830Sbrian return datalink_UpdateSet(d, r, w, e, n); 28736285Sbrian } else { 28836465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 28936285Sbrian dl->cfg.dial.max) 29046686Sbrian log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 29144468Sbrian dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 29236285Sbrian else 29346686Sbrian log_Printf(LogCHAT, "Failed to open device\n"); 29436285Sbrian 29536285Sbrian if (dl->bundle->CleaningUp || 29636465Sbrian (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 29744468Sbrian dl->cfg.dial.max && dl->dial.tries == 0)) { 29836285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 29936285Sbrian dl->reconnect_tries = 0; 30044468Sbrian dl->dial.tries = -1; 30138200Sbrian log_WritePrompts(dl, "Failed to open %s\n", 30238200Sbrian dl->physical->name.full); 30336285Sbrian bundle_LinkClosed(dl->bundle, dl); 30436285Sbrian } 30538200Sbrian if (!dl->bundle->CleaningUp) { 30644468Sbrian int timeout; 30744468Sbrian 30844468Sbrian timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 30938200Sbrian log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 31044261Sbrian dl->physical->name.full, timeout); 31138200Sbrian } 31236285Sbrian } 31336285Sbrian } 31436285Sbrian break; 31536285Sbrian 31649472Sbrian case DATALINK_CARRIER: 31749472Sbrian /* Wait for carrier on the device */ 31849472Sbrian switch (physical_AwaitCarrier(dl->physical)) { 31949472Sbrian case CARRIER_PENDING: 32049472Sbrian log_Printf(LogDEBUG, "Waiting for carrier\n"); 32149472Sbrian return 0; /* A device timer is running to wake us up again */ 32249472Sbrian 32349472Sbrian case CARRIER_OK: 32451978Sbrian if (dl->script.run) { 32551978Sbrian datalink_NewState(dl, DATALINK_LOGIN); 32652488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, NULL); 32751978Sbrian } else 32851978Sbrian datalink_LoginDone(dl); 32949472Sbrian return datalink_UpdateSet(d, r, w, e, n); 33049472Sbrian 33149472Sbrian case CARRIER_LOST: 33249472Sbrian physical_Offline(dl->physical); /* Is this required ? */ 33351978Sbrian if (dl->script.run) { 33451978Sbrian datalink_NewState(dl, DATALINK_HANGUP); 33552488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 33653070Sbrian return datalink_UpdateSet(d, r, w, e, n); 33753070Sbrian } else { 33851978Sbrian datalink_HangupDone(dl); 33953070Sbrian return 0; /* Maybe bundle_CleanDatalinks() has something to do */ 34053070Sbrian } 34149472Sbrian } 34249472Sbrian 34336285Sbrian case DATALINK_HANGUP: 34436285Sbrian case DATALINK_DIAL: 34552488Sbrian case DATALINK_LOGOUT: 34636285Sbrian case DATALINK_LOGIN: 34736285Sbrian result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 34836285Sbrian switch (dl->chat.state) { 34936285Sbrian case CHAT_DONE: 35036285Sbrian /* script succeeded */ 35136285Sbrian switch(dl->state) { 35236285Sbrian case DATALINK_HANGUP: 35336285Sbrian datalink_HangupDone(dl); 35436285Sbrian break; 35536285Sbrian case DATALINK_DIAL: 35649472Sbrian datalink_NewState(dl, DATALINK_CARRIER); 35736285Sbrian return datalink_UpdateSet(d, r, w, e, n); 35852488Sbrian case DATALINK_LOGOUT: 35952488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 36052488Sbrian physical_Offline(dl->physical); 36152488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 36252488Sbrian return datalink_UpdateSet(d, r, w, e, n); 36336285Sbrian case DATALINK_LOGIN: 36442390Sbrian dl->phone.alt = NULL; 36536285Sbrian datalink_LoginDone(dl); 36642905Sbrian return datalink_UpdateSet(d, r, w, e, n); 36736285Sbrian } 36836285Sbrian break; 36936285Sbrian case CHAT_FAILED: 37036285Sbrian /* Going down - script failed */ 37136285Sbrian log_Printf(LogWARN, "Chat script failed\n"); 37236285Sbrian switch(dl->state) { 37336285Sbrian case DATALINK_HANGUP: 37436285Sbrian datalink_HangupDone(dl); 37536285Sbrian break; 37636285Sbrian case DATALINK_DIAL: 37752488Sbrian case DATALINK_LOGOUT: 37836285Sbrian case DATALINK_LOGIN: 37936285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 38052488Sbrian physical_Offline(dl->physical); 38152488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 38236285Sbrian return datalink_UpdateSet(d, r, w, e, n); 38336285Sbrian } 38436285Sbrian break; 38536285Sbrian } 38636285Sbrian break; 38736285Sbrian 38836285Sbrian case DATALINK_READY: 38936285Sbrian case DATALINK_LCP: 39036285Sbrian case DATALINK_AUTH: 39138174Sbrian case DATALINK_CBCP: 39236285Sbrian case DATALINK_OPEN: 39343888Sbrian result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 39443888Sbrian descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 39536285Sbrian break; 39636285Sbrian } 39736285Sbrian return result; 39836285Sbrian} 39936285Sbrian 40036285Sbrianint 40136285Sbriandatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 40236285Sbrian{ 40336285Sbrian return physical_RemoveFromSet(dl->physical, r, w, e); 40436285Sbrian} 40536285Sbrian 40636285Sbrianstatic int 40736285Sbriandatalink_IsSet(struct descriptor *d, const fd_set *fdset) 40836285Sbrian{ 40936285Sbrian struct datalink *dl = descriptor2datalink(d); 41036285Sbrian 41136285Sbrian switch (dl->state) { 41236285Sbrian case DATALINK_CLOSED: 41336285Sbrian case DATALINK_OPENING: 41436285Sbrian break; 41536285Sbrian 41636285Sbrian case DATALINK_HANGUP: 41736285Sbrian case DATALINK_DIAL: 41852488Sbrian case DATALINK_LOGOUT: 41936285Sbrian case DATALINK_LOGIN: 42036285Sbrian return descriptor_IsSet(&dl->chat.desc, fdset); 42136285Sbrian 42236285Sbrian case DATALINK_READY: 42336285Sbrian case DATALINK_LCP: 42436285Sbrian case DATALINK_AUTH: 42538174Sbrian case DATALINK_CBCP: 42636285Sbrian case DATALINK_OPEN: 42743888Sbrian return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 42843888Sbrian descriptor_IsSet(&dl->physical->desc, fdset); 42936285Sbrian } 43036285Sbrian return 0; 43136285Sbrian} 43236285Sbrian 43336285Sbrianstatic void 43436285Sbriandatalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 43536285Sbrian{ 43636285Sbrian struct datalink *dl = descriptor2datalink(d); 43736285Sbrian 43836285Sbrian switch (dl->state) { 43936285Sbrian case DATALINK_CLOSED: 44036285Sbrian case DATALINK_OPENING: 44136285Sbrian break; 44236285Sbrian 44336285Sbrian case DATALINK_HANGUP: 44436285Sbrian case DATALINK_DIAL: 44552488Sbrian case DATALINK_LOGOUT: 44636285Sbrian case DATALINK_LOGIN: 44736285Sbrian descriptor_Read(&dl->chat.desc, bundle, fdset); 44836285Sbrian break; 44936285Sbrian 45036285Sbrian case DATALINK_READY: 45136285Sbrian case DATALINK_LCP: 45236285Sbrian case DATALINK_AUTH: 45338174Sbrian case DATALINK_CBCP: 45436285Sbrian case DATALINK_OPEN: 45543888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 45643888Sbrian descriptor_Read(&dl->chap.desc, bundle, fdset); 45743888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 45843888Sbrian descriptor_Read(&dl->physical->desc, bundle, fdset); 45936285Sbrian break; 46036285Sbrian } 46136285Sbrian} 46236285Sbrian 46337141Sbrianstatic int 46436285Sbriandatalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 46536285Sbrian{ 46636285Sbrian struct datalink *dl = descriptor2datalink(d); 46737141Sbrian int result = 0; 46836285Sbrian 46936285Sbrian switch (dl->state) { 47036285Sbrian case DATALINK_CLOSED: 47136285Sbrian case DATALINK_OPENING: 47236285Sbrian break; 47336285Sbrian 47436285Sbrian case DATALINK_HANGUP: 47536285Sbrian case DATALINK_DIAL: 47652488Sbrian case DATALINK_LOGOUT: 47736285Sbrian case DATALINK_LOGIN: 47837141Sbrian result = descriptor_Write(&dl->chat.desc, bundle, fdset); 47936285Sbrian break; 48036285Sbrian 48136285Sbrian case DATALINK_READY: 48236285Sbrian case DATALINK_LCP: 48336285Sbrian case DATALINK_AUTH: 48438174Sbrian case DATALINK_CBCP: 48536285Sbrian case DATALINK_OPEN: 48643888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 48743888Sbrian result += descriptor_Write(&dl->chap.desc, bundle, fdset); 48843888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 48943888Sbrian result += descriptor_Write(&dl->physical->desc, bundle, fdset); 49036285Sbrian break; 49136285Sbrian } 49237141Sbrian 49337141Sbrian return result; 49436285Sbrian} 49536285Sbrian 49636285Sbrianstatic void 49737007Sbriandatalink_ComeDown(struct datalink *dl, int how) 49836285Sbrian{ 49937007Sbrian if (how != CLOSE_NORMAL) { 50044468Sbrian dl->dial.tries = -1; 50136285Sbrian dl->reconnect_tries = 0; 50237012Sbrian if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 50337007Sbrian dl->stayonline = 1; 50436285Sbrian } 50536285Sbrian 50637012Sbrian if (dl->state >= DATALINK_READY && dl->stayonline) { 50737007Sbrian dl->stayonline = 0; 50847061Sbrian physical_StopDeviceTimer(dl->physical); 50937007Sbrian datalink_NewState(dl, DATALINK_READY); 51037007Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 51146686Sbrian physical_Offline(dl->physical); 51236285Sbrian if (dl->script.run && dl->state != DATALINK_OPENING) { 51352488Sbrian if (dl->state == DATALINK_LOGOUT) { 51452488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 51552488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 51652488Sbrian } else { 51752488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 51852488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.logout, NULL); 51952488Sbrian } 52036285Sbrian } else 52136285Sbrian datalink_HangupDone(dl); 52236285Sbrian } 52336285Sbrian} 52436285Sbrian 52536285Sbrianstatic void 52636285Sbriandatalink_LayerStart(void *v, struct fsm *fp) 52736285Sbrian{ 52836285Sbrian /* The given FSM is about to start up ! */ 52936285Sbrian struct datalink *dl = (struct datalink *)v; 53036285Sbrian 53136285Sbrian if (fp->proto == PROTO_LCP) 53236285Sbrian (*dl->parent->LayerStart)(dl->parent->object, fp); 53336285Sbrian} 53436285Sbrian 53536285Sbrianstatic void 53636285Sbriandatalink_LayerUp(void *v, struct fsm *fp) 53736285Sbrian{ 53836285Sbrian /* The given fsm is now up */ 53936285Sbrian struct datalink *dl = (struct datalink *)v; 54044106Sbrian struct lcp *lcp = &dl->physical->link.lcp; 54136285Sbrian 54236285Sbrian if (fp->proto == PROTO_LCP) { 54343693Sbrian datalink_GotAuthname(dl, ""); 54444106Sbrian lcp->auth_ineed = lcp->want_auth; 54544106Sbrian lcp->auth_iwait = lcp->his_auth; 54644106Sbrian if (lcp->his_auth || lcp->want_auth) { 54745350Sbrian if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 54836285Sbrian bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 54936285Sbrian log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 55044106Sbrian Auth2Nam(lcp->his_auth, lcp->his_authtype), 55144106Sbrian Auth2Nam(lcp->want_auth, lcp->want_authtype)); 55244106Sbrian if (lcp->his_auth == PROTO_PAP) 55343693Sbrian auth_StartReq(&dl->pap); 55444106Sbrian if (lcp->want_auth == PROTO_CHAP) 55543693Sbrian auth_StartReq(&dl->chap.auth); 55636285Sbrian } else 55736285Sbrian datalink_AuthOk(dl); 55836285Sbrian } 55936285Sbrian} 56036285Sbrian 56144094Sbrianstatic void 56244094Sbriandatalink_AuthReInit(struct datalink *dl) 56344094Sbrian{ 56444094Sbrian auth_StopTimer(&dl->pap); 56544094Sbrian auth_StopTimer(&dl->chap.auth); 56644094Sbrian chap_ReInit(&dl->chap); 56744094Sbrian} 56844094Sbrian 56936285Sbrianvoid 57043693Sbriandatalink_GotAuthname(struct datalink *dl, const char *name) 57136285Sbrian{ 57243693Sbrian strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 57343693Sbrian dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 57436285Sbrian} 57536285Sbrian 57636285Sbrianvoid 57738174Sbriandatalink_NCPUp(struct datalink *dl) 57836285Sbrian{ 57937320Sbrian int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 58036310Sbrian 58136285Sbrian if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 58236285Sbrian /* we've authenticated in multilink mode ! */ 58336285Sbrian switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 58436285Sbrian case MP_LINKSENT: 58536285Sbrian /* We've handed the link off to another ppp (well, we will soon) ! */ 58636285Sbrian return; 58736285Sbrian case MP_UP: 58836285Sbrian /* First link in the bundle */ 58938174Sbrian auth_Select(dl->bundle, dl->peer.authname); 59049434Sbrian bundle_CalculateBandwidth(dl->bundle); 59136285Sbrian /* fall through */ 59236285Sbrian case MP_ADDED: 59336285Sbrian /* We're in multilink mode ! */ 59436310Sbrian dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 59549434Sbrian bundle_CalculateBandwidth(dl->bundle); 59636285Sbrian break; 59736285Sbrian case MP_FAILED: 59836285Sbrian datalink_AuthNotOk(dl); 59936285Sbrian return; 60036285Sbrian } 60136285Sbrian } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 60236285Sbrian log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 60337160Sbrian datalink_NewState(dl, DATALINK_OPEN); 60449434Sbrian bundle_CalculateBandwidth(dl->bundle); 60537160Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 60636285Sbrian return; 60736285Sbrian } else { 60836285Sbrian dl->bundle->ncp.mp.peer = dl->peer; 60936285Sbrian ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 61038174Sbrian auth_Select(dl->bundle, dl->peer.authname); 61136285Sbrian } 61236285Sbrian 61337320Sbrian if (ccpok) { 61437320Sbrian fsm_Up(&dl->physical->link.ccp.fsm); 61537320Sbrian fsm_Open(&dl->physical->link.ccp.fsm); 61637320Sbrian } 61736285Sbrian datalink_NewState(dl, DATALINK_OPEN); 61836285Sbrian bundle_NewPhase(dl->bundle, PHASE_NETWORK); 61936285Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 62036285Sbrian} 62136285Sbrian 62236285Sbrianvoid 62338174Sbriandatalink_CBCPComplete(struct datalink *dl) 62438174Sbrian{ 62538174Sbrian datalink_NewState(dl, DATALINK_LCP); 62644094Sbrian datalink_AuthReInit(dl); 62738174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 62838174Sbrian} 62938174Sbrian 63038174Sbrianvoid 63138174Sbriandatalink_CBCPFailed(struct datalink *dl) 63238174Sbrian{ 63338174Sbrian cbcp_Down(&dl->cbcp); 63438174Sbrian datalink_CBCPComplete(dl); 63538174Sbrian} 63638174Sbrian 63738174Sbrianvoid 63838174Sbriandatalink_AuthOk(struct datalink *dl) 63938174Sbrian{ 64042600Sbrian if ((dl->physical->link.lcp.his_callback.opmask & 64142600Sbrian CALLBACK_BIT(CALLBACK_CBCP) || 64242600Sbrian dl->physical->link.lcp.want_callback.opmask & 64342600Sbrian CALLBACK_BIT(CALLBACK_CBCP)) && 64442600Sbrian !(dl->physical->link.lcp.want_callback.opmask & 64542600Sbrian CALLBACK_BIT(CALLBACK_AUTH))) { 64642600Sbrian /* We must have agreed CBCP if AUTH isn't there any more */ 64738174Sbrian datalink_NewState(dl, DATALINK_CBCP); 64838174Sbrian cbcp_Up(&dl->cbcp); 64938174Sbrian } else if (dl->physical->link.lcp.want_callback.opmask) { 65042600Sbrian /* It's not CBCP */ 65138174Sbrian log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 65238174Sbrian datalink_NewState(dl, DATALINK_LCP); 65344094Sbrian datalink_AuthReInit(dl); 65438174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 65538174Sbrian } else 65638174Sbrian switch (dl->physical->link.lcp.his_callback.opmask) { 65738174Sbrian case 0: 65838174Sbrian datalink_NCPUp(dl); 65938174Sbrian break; 66038174Sbrian 66138174Sbrian case CALLBACK_BIT(CALLBACK_AUTH): 66238174Sbrian auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 66338174Sbrian sizeof dl->cbcp.fsm.phone); 66438174Sbrian if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 66538174Sbrian log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 66638174Sbrian dl->peer.authname); 66738174Sbrian *dl->cbcp.fsm.phone = '\0'; 66838174Sbrian } else { 66938174Sbrian char *ptr = strchr(dl->cbcp.fsm.phone, ','); 67038174Sbrian if (ptr) 67138174Sbrian *ptr = '\0'; /* Call back on the first number */ 67238174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 67338174Sbrian dl->cbcp.fsm.phone); 67438174Sbrian dl->cbcp.required = 1; 67538174Sbrian } 67638174Sbrian dl->cbcp.fsm.delay = 0; 67738174Sbrian datalink_NewState(dl, DATALINK_LCP); 67844094Sbrian datalink_AuthReInit(dl); 67938174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 68038174Sbrian break; 68138174Sbrian 68238174Sbrian case CALLBACK_BIT(CALLBACK_E164): 68338174Sbrian strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 68438174Sbrian sizeof dl->cbcp.fsm.phone - 1); 68538174Sbrian dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 68638174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 68738174Sbrian dl->cbcp.fsm.phone); 68838174Sbrian dl->cbcp.required = 1; 68938174Sbrian dl->cbcp.fsm.delay = 0; 69038174Sbrian datalink_NewState(dl, DATALINK_LCP); 69144094Sbrian datalink_AuthReInit(dl); 69238174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 69338174Sbrian break; 69438174Sbrian 69538174Sbrian default: 69638174Sbrian log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 69738174Sbrian dl->name); 69838174Sbrian datalink_NewState(dl, DATALINK_LCP); 69944094Sbrian datalink_AuthReInit(dl); 70038174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 70138174Sbrian break; 70238174Sbrian } 70338174Sbrian} 70438174Sbrian 70538174Sbrianvoid 70636285Sbriandatalink_AuthNotOk(struct datalink *dl) 70736285Sbrian{ 70836285Sbrian datalink_NewState(dl, DATALINK_LCP); 70944094Sbrian datalink_AuthReInit(dl); 71036285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 71136285Sbrian} 71236285Sbrian 71336285Sbrianstatic void 71436285Sbriandatalink_LayerDown(void *v, struct fsm *fp) 71536285Sbrian{ 71636285Sbrian /* The given FSM has been told to come down */ 71736285Sbrian struct datalink *dl = (struct datalink *)v; 71836285Sbrian 71936285Sbrian if (fp->proto == PROTO_LCP) { 72036285Sbrian switch (dl->state) { 72136285Sbrian case DATALINK_OPEN: 72236285Sbrian peerid_Init(&dl->peer); 72337060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 72436928Sbrian datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 72536285Sbrian (*dl->parent->LayerDown)(dl->parent->object, fp); 72638174Sbrian /* fall through (just in case) */ 72736285Sbrian 72838174Sbrian case DATALINK_CBCP: 72938174Sbrian if (!dl->cbcp.required) 73038174Sbrian cbcp_Down(&dl->cbcp); 73138174Sbrian /* fall through (just in case) */ 73238174Sbrian 73336285Sbrian case DATALINK_AUTH: 73436285Sbrian timer_Stop(&dl->pap.authtimer); 73536285Sbrian timer_Stop(&dl->chap.auth.authtimer); 73636285Sbrian } 73736285Sbrian datalink_NewState(dl, DATALINK_LCP); 73844094Sbrian datalink_AuthReInit(dl); 73936285Sbrian } 74036285Sbrian} 74136285Sbrian 74236285Sbrianstatic void 74336285Sbriandatalink_LayerFinish(void *v, struct fsm *fp) 74436285Sbrian{ 74536285Sbrian /* The given fsm is now down */ 74636285Sbrian struct datalink *dl = (struct datalink *)v; 74736285Sbrian 74836285Sbrian if (fp->proto == PROTO_LCP) { 74937060Sbrian fsm2initial(fp); 75036285Sbrian (*dl->parent->LayerFinish)(dl->parent->object, fp); 75137007Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 75236285Sbrian } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 75336285Sbrian fsm_Open(fp); /* CCP goes to ST_STOPPED */ 75436285Sbrian} 75536285Sbrian 75636285Sbrianstruct datalink * 75736285Sbriandatalink_Create(const char *name, struct bundle *bundle, int type) 75836285Sbrian{ 75936285Sbrian struct datalink *dl; 76036285Sbrian 76136285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 76236285Sbrian if (dl == NULL) 76336285Sbrian return dl; 76436285Sbrian 76536285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 76636285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 76736285Sbrian dl->desc.IsSet = datalink_IsSet; 76836285Sbrian dl->desc.Read = datalink_Read; 76936285Sbrian dl->desc.Write = datalink_Write; 77036285Sbrian 77136285Sbrian dl->state = DATALINK_CLOSED; 77236285Sbrian 77336285Sbrian *dl->cfg.script.dial = '\0'; 77436285Sbrian *dl->cfg.script.login = '\0'; 77552488Sbrian *dl->cfg.script.logout = '\0'; 77636285Sbrian *dl->cfg.script.hangup = '\0'; 77736285Sbrian *dl->cfg.phone.list = '\0'; 77836285Sbrian *dl->phone.list = '\0'; 77936285Sbrian dl->phone.next = NULL; 78036285Sbrian dl->phone.alt = NULL; 78136285Sbrian dl->phone.chosen = "N/A"; 78237007Sbrian dl->stayonline = 0; 78336285Sbrian dl->script.run = 1; 78436285Sbrian dl->script.packetmode = 1; 78536285Sbrian mp_linkInit(&dl->mp); 78636285Sbrian 78736285Sbrian dl->bundle = bundle; 78836285Sbrian dl->next = NULL; 78936285Sbrian 79044468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 79136285Sbrian 79244468Sbrian dl->dial.tries = 0; 79336285Sbrian dl->cfg.dial.max = 1; 79436285Sbrian dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 79536285Sbrian dl->cfg.dial.timeout = DIAL_TIMEOUT; 79644468Sbrian dl->cfg.dial.inc = 0; 79744468Sbrian dl->cfg.dial.maxinc = 10; 79836285Sbrian 79936285Sbrian dl->reconnect_tries = 0; 80036285Sbrian dl->cfg.reconnect.max = 0; 80136285Sbrian dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 80236285Sbrian 80338174Sbrian dl->cfg.callback.opmask = 0; 80438174Sbrian dl->cfg.cbcp.delay = 0; 80538174Sbrian *dl->cfg.cbcp.phone = '\0'; 80638174Sbrian dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 80738174Sbrian 80836285Sbrian dl->name = strdup(name); 80936285Sbrian peerid_Init(&dl->peer); 81036285Sbrian dl->parent = &bundle->fsm; 81136285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 81236285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 81336285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 81436285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 81536285Sbrian dl->fsmp.object = dl; 81636285Sbrian 81746686Sbrian if ((dl->physical = physical_Create(dl, type)) == NULL) { 81836285Sbrian free(dl->name); 81936285Sbrian free(dl); 82036285Sbrian return NULL; 82136285Sbrian } 82243693Sbrian 82343693Sbrian pap_Init(&dl->pap, dl->physical); 82443693Sbrian chap_Init(&dl->chap, dl->physical); 82538174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 82636285Sbrian 82752488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 82852488Sbrian chat_Init(&dl->chat, dl->physical, NULL, NULL); 82952488Sbrian 83036285Sbrian log_Printf(LogPHASE, "%s: Created in %s state\n", 83136285Sbrian dl->name, datalink_State(dl)); 83236285Sbrian 83336285Sbrian return dl; 83436285Sbrian} 83536285Sbrian 83636285Sbrianstruct datalink * 83736285Sbriandatalink_Clone(struct datalink *odl, const char *name) 83836285Sbrian{ 83936285Sbrian struct datalink *dl; 84036285Sbrian 84136285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 84236285Sbrian if (dl == NULL) 84336285Sbrian return dl; 84436285Sbrian 84536285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 84636285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 84736285Sbrian dl->desc.IsSet = datalink_IsSet; 84836285Sbrian dl->desc.Read = datalink_Read; 84936285Sbrian dl->desc.Write = datalink_Write; 85036285Sbrian 85136285Sbrian dl->state = DATALINK_CLOSED; 85236285Sbrian 85336285Sbrian memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 85436285Sbrian mp_linkInit(&dl->mp); 85536285Sbrian *dl->phone.list = '\0'; 85636285Sbrian dl->phone.next = NULL; 85736285Sbrian dl->phone.alt = NULL; 85836285Sbrian dl->phone.chosen = "N/A"; 85936285Sbrian dl->bundle = odl->bundle; 86036285Sbrian dl->next = NULL; 86144468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 86244468Sbrian dl->dial.tries = 0; 86336285Sbrian dl->reconnect_tries = 0; 86436285Sbrian dl->name = strdup(name); 86536285Sbrian peerid_Init(&dl->peer); 86636285Sbrian dl->parent = odl->parent; 86736285Sbrian memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 86836285Sbrian dl->fsmp.object = dl; 86936285Sbrian 87046686Sbrian if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { 87136285Sbrian free(dl->name); 87236285Sbrian free(dl); 87336285Sbrian return NULL; 87436285Sbrian } 87543693Sbrian pap_Init(&dl->pap, dl->physical); 87644305Sbrian dl->pap.cfg = odl->pap.cfg; 87743693Sbrian 87843693Sbrian chap_Init(&dl->chap, dl->physical); 87944305Sbrian dl->chap.auth.cfg = odl->chap.auth.cfg; 88043693Sbrian 88136285Sbrian memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 88236285Sbrian memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 88336285Sbrian sizeof dl->physical->link.lcp.cfg); 88436285Sbrian memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 88536285Sbrian sizeof dl->physical->link.ccp.cfg); 88636285Sbrian memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 88736285Sbrian sizeof dl->physical->async.cfg); 88836285Sbrian 88938174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 89036285Sbrian 89152488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 89252488Sbrian chat_Init(&dl->chat, dl->physical, NULL, NULL); 89352488Sbrian 89436285Sbrian log_Printf(LogPHASE, "%s: Cloned in %s state\n", 89536285Sbrian dl->name, datalink_State(dl)); 89636285Sbrian 89736285Sbrian return dl; 89836285Sbrian} 89936285Sbrian 90036285Sbrianstruct datalink * 90136285Sbriandatalink_Destroy(struct datalink *dl) 90236285Sbrian{ 90336285Sbrian struct datalink *result; 90436285Sbrian 90536285Sbrian if (dl->state != DATALINK_CLOSED) { 90636285Sbrian log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 90736285Sbrian datalink_State(dl)); 90836285Sbrian switch (dl->state) { 90936285Sbrian case DATALINK_HANGUP: 91036285Sbrian case DATALINK_DIAL: 91136285Sbrian case DATALINK_LOGIN: 91236285Sbrian chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 91336285Sbrian break; 91436285Sbrian } 91536285Sbrian } 91636285Sbrian 91744468Sbrian timer_Stop(&dl->dial.timer); 91836285Sbrian result = dl->next; 91946686Sbrian physical_Destroy(dl->physical); 92036285Sbrian free(dl->name); 92136285Sbrian free(dl); 92236285Sbrian 92336285Sbrian return result; 92436285Sbrian} 92536285Sbrian 92636285Sbrianvoid 92736285Sbriandatalink_Up(struct datalink *dl, int runscripts, int packetmode) 92836285Sbrian{ 92936285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 93036285Sbrian /* Ignore scripts */ 93136285Sbrian runscripts = 0; 93236285Sbrian 93336285Sbrian switch (dl->state) { 93436285Sbrian case DATALINK_CLOSED: 93536285Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 93636285Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 93736285Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 93836285Sbrian datalink_NewState(dl, DATALINK_OPENING); 93936285Sbrian dl->reconnect_tries = 94036285Sbrian dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 94144468Sbrian dl->dial.tries = dl->cfg.dial.max; 94236285Sbrian dl->script.run = runscripts; 94336285Sbrian dl->script.packetmode = packetmode; 94436285Sbrian break; 94536285Sbrian 94636285Sbrian case DATALINK_OPENING: 94736285Sbrian if (!dl->script.run && runscripts) 94836285Sbrian dl->script.run = 1; 94936285Sbrian /* fall through */ 95036285Sbrian 95136285Sbrian case DATALINK_DIAL: 95236285Sbrian case DATALINK_LOGIN: 95336285Sbrian case DATALINK_READY: 95436285Sbrian if (!dl->script.packetmode && packetmode) { 95536285Sbrian dl->script.packetmode = 1; 95636285Sbrian if (dl->state == DATALINK_READY) 95736285Sbrian datalink_LoginDone(dl); 95836285Sbrian } 95936285Sbrian break; 96036285Sbrian } 96136285Sbrian} 96236285Sbrian 96336285Sbrianvoid 96437007Sbriandatalink_Close(struct datalink *dl, int how) 96536285Sbrian{ 96636285Sbrian /* Please close */ 96736285Sbrian switch (dl->state) { 96836285Sbrian case DATALINK_OPEN: 96936285Sbrian peerid_Init(&dl->peer); 97037060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 97136285Sbrian /* fall through */ 97236285Sbrian 97338174Sbrian case DATALINK_CBCP: 97436285Sbrian case DATALINK_AUTH: 97536285Sbrian case DATALINK_LCP: 97644094Sbrian datalink_AuthReInit(dl); 97736285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 97837007Sbrian if (how != CLOSE_NORMAL) { 97944468Sbrian dl->dial.tries = -1; 98036285Sbrian dl->reconnect_tries = 0; 98137007Sbrian if (how == CLOSE_LCP) 98237007Sbrian dl->stayonline = 1; 98336285Sbrian } 98452029Sbrian break; 98536285Sbrian 98636285Sbrian default: 98737007Sbrian datalink_ComeDown(dl, how); 98836285Sbrian } 98936285Sbrian} 99036285Sbrian 99136285Sbrianvoid 99237007Sbriandatalink_Down(struct datalink *dl, int how) 99336285Sbrian{ 99436285Sbrian /* Carrier is lost */ 99536285Sbrian switch (dl->state) { 99636285Sbrian case DATALINK_OPEN: 99736285Sbrian peerid_Init(&dl->peer); 99837060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 99936285Sbrian /* fall through */ 100036285Sbrian 100138174Sbrian case DATALINK_CBCP: 100236285Sbrian case DATALINK_AUTH: 100336285Sbrian case DATALINK_LCP: 100437060Sbrian fsm2initial(&dl->physical->link.lcp.fsm); 100536285Sbrian /* fall through */ 100636285Sbrian 100736285Sbrian default: 100837007Sbrian datalink_ComeDown(dl, how); 100936285Sbrian } 101036285Sbrian} 101136285Sbrian 101236285Sbrianvoid 101336285Sbriandatalink_StayDown(struct datalink *dl) 101436285Sbrian{ 101536285Sbrian dl->reconnect_tries = 0; 101636285Sbrian} 101736285Sbrian 101837007Sbrianvoid 101937007Sbriandatalink_DontHangup(struct datalink *dl) 102037007Sbrian{ 102137012Sbrian if (dl->state >= DATALINK_LCP) 102237012Sbrian dl->stayonline = 1; 102337007Sbrian} 102437007Sbrian 102536285Sbrianint 102636285Sbriandatalink_Show(struct cmdargs const *arg) 102736285Sbrian{ 102836285Sbrian prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 102938174Sbrian prompt_Printf(arg->prompt, " State: %s\n", 103036285Sbrian datalink_State(arg->cx)); 103138174Sbrian prompt_Printf(arg->prompt, " Peer name: "); 103236285Sbrian if (*arg->cx->peer.authname) 103336285Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 103436285Sbrian else if (arg->cx->state == DATALINK_OPEN) 103536285Sbrian prompt_Printf(arg->prompt, "None requested\n"); 103636285Sbrian else 103736285Sbrian prompt_Printf(arg->prompt, "N/A\n"); 103838174Sbrian prompt_Printf(arg->prompt, " Discriminator: %s\n", 103936285Sbrian mp_Enddisc(arg->cx->peer.enddisc.class, 104036285Sbrian arg->cx->peer.enddisc.address, 104136285Sbrian arg->cx->peer.enddisc.len)); 104236285Sbrian 104336285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 104438174Sbrian prompt_Printf(arg->prompt, " Phone List: %s\n", 104536285Sbrian arg->cx->cfg.phone.list); 104636285Sbrian if (arg->cx->cfg.dial.max) 104738174Sbrian prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 104836285Sbrian arg->cx->cfg.dial.max); 104936285Sbrian else 105038174Sbrian prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 105144261Sbrian if (arg->cx->cfg.dial.next_timeout >= 0) 105236285Sbrian prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 105336285Sbrian else 105436285Sbrian prompt_Printf(arg->prompt, "random/"); 105544261Sbrian if (arg->cx->cfg.dial.timeout >= 0) 105636285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 105736285Sbrian else 105836285Sbrian prompt_Printf(arg->prompt, "random\n"); 105938174Sbrian prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 106036285Sbrian arg->cx->cfg.reconnect.max); 106136285Sbrian if (arg->cx->cfg.reconnect.timeout > 0) 106236285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 106336285Sbrian else 106436285Sbrian prompt_Printf(arg->prompt, "random\n"); 106538174Sbrian prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 106638174Sbrian PHYS_DIRECT ? "accepted: " : "requested:"); 106738174Sbrian if (!arg->cx->cfg.callback.opmask) 106838174Sbrian prompt_Printf(arg->prompt, "none\n"); 106938174Sbrian else { 107038174Sbrian int comma = 0; 107138174Sbrian 107238174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 107338174Sbrian prompt_Printf(arg->prompt, "none"); 107438174Sbrian comma = 1; 107538174Sbrian } 107638174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 107738174Sbrian prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 107838174Sbrian comma = 1; 107938174Sbrian } 108038174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 108138174Sbrian prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 108238174Sbrian if (arg->cx->physical->type != PHYS_DIRECT) 108338174Sbrian prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 108438174Sbrian comma = 1; 108538174Sbrian } 108638174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 108738174Sbrian prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 108838174Sbrian prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 108938174Sbrian arg->cx->cfg.cbcp.delay); 109040483Sbrian prompt_Printf(arg->prompt, " phone: "); 109140483Sbrian if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 109240483Sbrian if (arg->cx->physical->type & PHYS_DIRECT) 109340483Sbrian prompt_Printf(arg->prompt, "Caller decides\n"); 109440483Sbrian else 109540483Sbrian prompt_Printf(arg->prompt, "Dialback server decides\n"); 109640483Sbrian } else 109740483Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 109838174Sbrian prompt_Printf(arg->prompt, " timeout: %lds\n", 109938174Sbrian arg->cx->cfg.cbcp.fsmretry); 110038174Sbrian } else 110138174Sbrian prompt_Printf(arg->prompt, "\n"); 110238174Sbrian } 110338174Sbrian 110438174Sbrian prompt_Printf(arg->prompt, " Dial Script: %s\n", 110536285Sbrian arg->cx->cfg.script.dial); 110638174Sbrian prompt_Printf(arg->prompt, " Login Script: %s\n", 110736285Sbrian arg->cx->cfg.script.login); 110852488Sbrian prompt_Printf(arg->prompt, " Logout Script: %s\n", 110952488Sbrian arg->cx->cfg.script.logout); 111038174Sbrian prompt_Printf(arg->prompt, " Hangup Script: %s\n", 111136285Sbrian arg->cx->cfg.script.hangup); 111236285Sbrian return 0; 111336285Sbrian} 111436285Sbrian 111536285Sbrianint 111636285Sbriandatalink_SetReconnect(struct cmdargs const *arg) 111736285Sbrian{ 111836285Sbrian if (arg->argc == arg->argn+2) { 111936285Sbrian arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 112036285Sbrian arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 112136285Sbrian return 0; 112236285Sbrian } 112336285Sbrian return -1; 112436285Sbrian} 112536285Sbrian 112636285Sbrianint 112736285Sbriandatalink_SetRedial(struct cmdargs const *arg) 112836285Sbrian{ 112944468Sbrian const char *sep, *osep; 113044468Sbrian int timeout, inc, maxinc, tries; 113136285Sbrian 113236285Sbrian if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 113336285Sbrian if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 113436285Sbrian (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 113536285Sbrian arg->cx->cfg.dial.timeout = -1; 113636285Sbrian randinit(); 113736285Sbrian } else { 113836285Sbrian timeout = atoi(arg->argv[arg->argn]); 113936285Sbrian 114036285Sbrian if (timeout >= 0) 114136285Sbrian arg->cx->cfg.dial.timeout = timeout; 114236285Sbrian else { 114336285Sbrian log_Printf(LogWARN, "Invalid redial timeout\n"); 114436285Sbrian return -1; 114536285Sbrian } 114636285Sbrian } 114736285Sbrian 114844468Sbrian sep = strchr(arg->argv[arg->argn], '+'); 114944468Sbrian if (sep) { 115044468Sbrian inc = atoi(++sep); 115144468Sbrian osep = sep; 115244468Sbrian if (inc >= 0) 115344468Sbrian arg->cx->cfg.dial.inc = inc; 115444468Sbrian else { 115544468Sbrian log_Printf(LogWARN, "Invalid timeout increment\n"); 115644468Sbrian return -1; 115744468Sbrian } 115844468Sbrian sep = strchr(sep, '-'); 115944468Sbrian if (sep) { 116044468Sbrian maxinc = atoi(++sep); 116144468Sbrian if (maxinc >= 0) 116244468Sbrian arg->cx->cfg.dial.maxinc = maxinc; 116344468Sbrian else { 116444468Sbrian log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 116544468Sbrian return -1; 116644468Sbrian } 116744468Sbrian } else { 116844468Sbrian /* Default timeout increment */ 116944468Sbrian arg->cx->cfg.dial.maxinc = 10; 117044468Sbrian sep = osep; 117144468Sbrian } 117244468Sbrian } else { 117344468Sbrian /* Default timeout increment & max increment */ 117444468Sbrian arg->cx->cfg.dial.inc = 0; 117544468Sbrian arg->cx->cfg.dial.maxinc = 10; 117644468Sbrian sep = arg->argv[arg->argn]; 117744468Sbrian } 117844468Sbrian 117944468Sbrian sep = strchr(sep, '.'); 118044468Sbrian if (sep) { 118144468Sbrian if (strcasecmp(++sep, "random") == 0) { 118236285Sbrian arg->cx->cfg.dial.next_timeout = -1; 118336285Sbrian randinit(); 118436285Sbrian } else { 118544468Sbrian timeout = atoi(sep); 118636285Sbrian if (timeout >= 0) 118736285Sbrian arg->cx->cfg.dial.next_timeout = timeout; 118836285Sbrian else { 118936285Sbrian log_Printf(LogWARN, "Invalid next redial timeout\n"); 119036285Sbrian return -1; 119136285Sbrian } 119236285Sbrian } 119336285Sbrian } else 119436285Sbrian /* Default next timeout */ 119536285Sbrian arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 119636285Sbrian 119736285Sbrian if (arg->argc == arg->argn+2) { 119836285Sbrian tries = atoi(arg->argv[arg->argn+1]); 119936285Sbrian 120036285Sbrian if (tries >= 0) { 120136285Sbrian arg->cx->cfg.dial.max = tries; 120236285Sbrian } else { 120336285Sbrian log_Printf(LogWARN, "Invalid retry value\n"); 120436285Sbrian return 1; 120536285Sbrian } 120636285Sbrian } 120736285Sbrian return 0; 120836285Sbrian } 120944468Sbrian 121036285Sbrian return -1; 121136285Sbrian} 121236285Sbrian 121336285Sbrianstatic const char *states[] = { 121436285Sbrian "closed", 121536285Sbrian "opening", 121636285Sbrian "hangup", 121736285Sbrian "dial", 121849472Sbrian "carrier", 121952488Sbrian "logout", 122036285Sbrian "login", 122136285Sbrian "ready", 122236285Sbrian "lcp", 122336285Sbrian "auth", 122438174Sbrian "cbcp", 122536285Sbrian "open" 122636285Sbrian}; 122736285Sbrian 122836285Sbrianconst char * 122936285Sbriandatalink_State(struct datalink *dl) 123036285Sbrian{ 123136285Sbrian if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 123236285Sbrian return "unknown"; 123336285Sbrian return states[dl->state]; 123436285Sbrian} 123536285Sbrian 123636285Sbrianstatic void 123736285Sbriandatalink_NewState(struct datalink *dl, int state) 123836285Sbrian{ 123936285Sbrian if (state != dl->state) { 124036285Sbrian if (state >= 0 && state < sizeof states / sizeof states[0]) { 124136285Sbrian log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 124236285Sbrian states[state]); 124336285Sbrian dl->state = state; 124436285Sbrian } else 124536285Sbrian log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 124636285Sbrian } 124736285Sbrian} 124836285Sbrian 124936285Sbrianstruct datalink * 125036285Sbrianiov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 125152942Sbrian int fd, int *auxfd, int *nauxfd) 125236285Sbrian{ 125336285Sbrian struct datalink *dl, *cdl; 125444305Sbrian struct fsm_retry copy; 125536285Sbrian char *oname; 125636285Sbrian 125736285Sbrian dl = (struct datalink *)iov[(*niov)++].iov_base; 125836285Sbrian dl->name = iov[*niov].iov_base; 125936285Sbrian 126036285Sbrian if (dl->name[DATALINK_MAXNAME-1]) { 126136285Sbrian dl->name[DATALINK_MAXNAME-1] = '\0'; 126236285Sbrian if (strlen(dl->name) == DATALINK_MAXNAME - 1) 126336285Sbrian log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 126436285Sbrian } 126536285Sbrian 126636285Sbrian /* Make sure the name is unique ! */ 126736285Sbrian oname = NULL; 126836285Sbrian do { 126936285Sbrian for (cdl = bundle->links; cdl; cdl = cdl->next) 127036285Sbrian if (!strcasecmp(dl->name, cdl->name)) { 127136285Sbrian if (oname) 127236285Sbrian free(datalink_NextName(dl)); 127336285Sbrian else 127436285Sbrian oname = datalink_NextName(dl); 127536285Sbrian break; /* Keep renaming 'till we have no conflicts */ 127636285Sbrian } 127736285Sbrian } while (cdl); 127836285Sbrian 127936285Sbrian if (oname) { 128036285Sbrian log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 128136285Sbrian free(oname); 128236285Sbrian } else { 128336285Sbrian dl->name = strdup(dl->name); 128436285Sbrian free(iov[*niov].iov_base); 128536285Sbrian } 128636285Sbrian (*niov)++; 128736285Sbrian 128836285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 128936285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 129036285Sbrian dl->desc.IsSet = datalink_IsSet; 129136285Sbrian dl->desc.Read = datalink_Read; 129236285Sbrian dl->desc.Write = datalink_Write; 129336285Sbrian 129436285Sbrian mp_linkInit(&dl->mp); 129536285Sbrian *dl->phone.list = '\0'; 129636285Sbrian dl->phone.next = NULL; 129736285Sbrian dl->phone.alt = NULL; 129836285Sbrian dl->phone.chosen = "N/A"; 129936285Sbrian 130036285Sbrian dl->bundle = bundle; 130136285Sbrian dl->next = NULL; 130244468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 130344468Sbrian dl->dial.tries = 0; 130436285Sbrian dl->reconnect_tries = 0; 130536285Sbrian dl->parent = &bundle->fsm; 130636285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 130736285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 130836285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 130936285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 131036285Sbrian dl->fsmp.object = dl; 131136285Sbrian 131252942Sbrian dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); 131336285Sbrian 131436285Sbrian if (!dl->physical) { 131536285Sbrian free(dl->name); 131636285Sbrian free(dl); 131736285Sbrian dl = NULL; 131836285Sbrian } else { 131944305Sbrian copy = dl->pap.cfg.fsm; 132043693Sbrian pap_Init(&dl->pap, dl->physical); 132144305Sbrian dl->pap.cfg.fsm = copy; 132243693Sbrian 132344305Sbrian copy = dl->chap.auth.cfg.fsm; 132443693Sbrian chap_Init(&dl->chap, dl->physical); 132544305Sbrian dl->chap.auth.cfg.fsm = copy; 132643693Sbrian 132738174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 132836285Sbrian 132952488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 133052488Sbrian chat_Init(&dl->chat, dl->physical, NULL, NULL); 133152488Sbrian 133236285Sbrian log_Printf(LogPHASE, "%s: Transferred in %s state\n", 133336285Sbrian dl->name, datalink_State(dl)); 133436285Sbrian } 133536285Sbrian 133636285Sbrian return dl; 133736285Sbrian} 133836285Sbrian 133936285Sbrianint 134036450Sbriandatalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 134153684Sbrian int *auxfd, int *nauxfd) 134236285Sbrian{ 134336285Sbrian /* If `dl' is NULL, we're allocating before a Fromiov() */ 134436285Sbrian int link_fd; 134536285Sbrian 134636285Sbrian if (dl) { 134744468Sbrian timer_Stop(&dl->dial.timer); 134838174Sbrian /* The following is purely for the sake of paranoia */ 134938174Sbrian cbcp_Down(&dl->cbcp); 135036285Sbrian timer_Stop(&dl->pap.authtimer); 135136285Sbrian timer_Stop(&dl->chap.auth.authtimer); 135236285Sbrian } 135336285Sbrian 135436285Sbrian if (*niov >= maxiov - 1) { 135536285Sbrian log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 135636285Sbrian if (dl) { 135736285Sbrian free(dl->name); 135836285Sbrian free(dl); 135936285Sbrian } 136036285Sbrian return -1; 136136285Sbrian } 136236285Sbrian 136353684Sbrian iov[*niov].iov_base = (void *)dl; 136436285Sbrian iov[(*niov)++].iov_len = sizeof *dl; 136553684Sbrian iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL; 136636285Sbrian iov[(*niov)++].iov_len = DATALINK_MAXNAME; 136736285Sbrian 136852942Sbrian link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, 136953684Sbrian nauxfd); 137036285Sbrian 137136285Sbrian if (link_fd == -1 && dl) { 137236285Sbrian free(dl->name); 137336285Sbrian free(dl); 137436285Sbrian } 137536285Sbrian 137636285Sbrian return link_fd; 137736285Sbrian} 137836285Sbrian 137936285Sbrianvoid 138036285Sbriandatalink_Rename(struct datalink *dl, const char *name) 138136285Sbrian{ 138236285Sbrian free(dl->name); 138336285Sbrian dl->physical->link.name = dl->name = strdup(name); 138436285Sbrian} 138536285Sbrian 138636285Sbrianchar * 138736285Sbriandatalink_NextName(struct datalink *dl) 138836285Sbrian{ 138936285Sbrian int f, n; 139036285Sbrian char *name, *oname; 139136285Sbrian 139236285Sbrian n = strlen(dl->name); 139336285Sbrian name = (char *)malloc(n+3); 139436285Sbrian for (f = n - 1; f >= 0; f--) 139536285Sbrian if (!isdigit(dl->name[f])) 139636285Sbrian break; 139736285Sbrian n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 139836285Sbrian sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 139936285Sbrian oname = dl->name; 140036345Sbrian dl->name = name; 140136345Sbrian /* our physical link name isn't updated (it probably isn't created yet) */ 140236285Sbrian return oname; 140336285Sbrian} 140436285Sbrian 140536285Sbrianint 140636285Sbriandatalink_SetMode(struct datalink *dl, int mode) 140736285Sbrian{ 140836285Sbrian if (!physical_SetMode(dl->physical, mode)) 140936285Sbrian return 0; 141036285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 141136285Sbrian dl->script.run = 0; 141236285Sbrian if (dl->physical->type == PHYS_DIRECT) 141336285Sbrian dl->reconnect_tries = 0; 141453830Sbrian if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) && 141553830Sbrian dl->state <= DATALINK_READY) 141636285Sbrian datalink_Up(dl, 1, 1); 141736285Sbrian return 1; 141836285Sbrian} 141944468Sbrian 142044468Sbrianint 142144468Sbriandatalink_GetDialTimeout(struct datalink *dl) 142244468Sbrian{ 142344468Sbrian int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 142444468Sbrian 142544468Sbrian if (dl->dial.incs < dl->cfg.dial.maxinc) 142644468Sbrian dl->dial.incs++; 142744468Sbrian 142844468Sbrian return result; 142944468Sbrian} 1430