datalink.c revision 53070
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 53070 1999-11-09 23:21:47Z 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: 25236465Sbrian if ((dl->physical->type & 25336465Sbrian (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 25447863Sbrian !dl->bundle->CleaningUp) 25536285Sbrian /* 25636465Sbrian * Our first time in - DEDICATED & DDIAL never come down, and 25736465Sbrian * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 25836465Sbrian * Go to DATALINK_OPENING via datalink_Up() and fall through. 25936285Sbrian */ 26036285Sbrian datalink_Up(dl, 1, 1); 26136285Sbrian else 26236285Sbrian break; 26336285Sbrian /* fall through */ 26436285Sbrian 26536285Sbrian case DATALINK_OPENING: 26644468Sbrian if (dl->dial.timer.state != TIMER_RUNNING) { 26744468Sbrian if (--dl->dial.tries < 0) 26844468Sbrian dl->dial.tries = 0; 26946686Sbrian if (physical_Open(dl->physical, dl->bundle) >= 0) { 27038200Sbrian log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 27138200Sbrian "Type `~?' for help\r\n", dl->name, 27238200Sbrian dl->physical->name.full); 27336285Sbrian if (dl->script.run) { 27436285Sbrian datalink_NewState(dl, DATALINK_DIAL); 27552488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 27649472Sbrian *dl->cfg.script.dial ? 27749472Sbrian datalink_ChoosePhoneNumber(dl) : ""); 27836465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 27936285Sbrian dl->cfg.dial.max) 28036285Sbrian log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 28144468Sbrian dl->name, dl->cfg.dial.max - dl->dial.tries, 28236285Sbrian dl->cfg.dial.max); 28336285Sbrian } else 28451978Sbrian datalink_NewState(dl, DATALINK_CARRIER); 28541830Sbrian return datalink_UpdateSet(d, r, w, e, n); 28636285Sbrian } else { 28736465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 28836285Sbrian dl->cfg.dial.max) 28946686Sbrian log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 29044468Sbrian dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 29136285Sbrian else 29246686Sbrian log_Printf(LogCHAT, "Failed to open device\n"); 29336285Sbrian 29436285Sbrian if (dl->bundle->CleaningUp || 29536465Sbrian (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 29644468Sbrian dl->cfg.dial.max && dl->dial.tries == 0)) { 29736285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 29836285Sbrian dl->reconnect_tries = 0; 29944468Sbrian dl->dial.tries = -1; 30038200Sbrian log_WritePrompts(dl, "Failed to open %s\n", 30138200Sbrian dl->physical->name.full); 30236285Sbrian bundle_LinkClosed(dl->bundle, dl); 30336285Sbrian } 30438200Sbrian if (!dl->bundle->CleaningUp) { 30544468Sbrian int timeout; 30644468Sbrian 30744468Sbrian timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 30838200Sbrian log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 30944261Sbrian dl->physical->name.full, timeout); 31038200Sbrian } 31136285Sbrian } 31236285Sbrian } 31336285Sbrian break; 31436285Sbrian 31549472Sbrian case DATALINK_CARRIER: 31649472Sbrian /* Wait for carrier on the device */ 31749472Sbrian switch (physical_AwaitCarrier(dl->physical)) { 31849472Sbrian case CARRIER_PENDING: 31949472Sbrian log_Printf(LogDEBUG, "Waiting for carrier\n"); 32049472Sbrian return 0; /* A device timer is running to wake us up again */ 32149472Sbrian 32249472Sbrian case CARRIER_OK: 32351978Sbrian if (dl->script.run) { 32451978Sbrian datalink_NewState(dl, DATALINK_LOGIN); 32552488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, NULL); 32651978Sbrian } else 32751978Sbrian datalink_LoginDone(dl); 32849472Sbrian return datalink_UpdateSet(d, r, w, e, n); 32949472Sbrian 33049472Sbrian case CARRIER_LOST: 33149472Sbrian physical_Offline(dl->physical); /* Is this required ? */ 33251978Sbrian if (dl->script.run) { 33351978Sbrian datalink_NewState(dl, DATALINK_HANGUP); 33452488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 33553070Sbrian return datalink_UpdateSet(d, r, w, e, n); 33653070Sbrian } else { 33751978Sbrian datalink_HangupDone(dl); 33853070Sbrian return 0; /* Maybe bundle_CleanDatalinks() has something to do */ 33953070Sbrian } 34049472Sbrian } 34149472Sbrian 34236285Sbrian case DATALINK_HANGUP: 34336285Sbrian case DATALINK_DIAL: 34452488Sbrian case DATALINK_LOGOUT: 34536285Sbrian case DATALINK_LOGIN: 34636285Sbrian result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 34736285Sbrian switch (dl->chat.state) { 34836285Sbrian case CHAT_DONE: 34936285Sbrian /* script succeeded */ 35036285Sbrian switch(dl->state) { 35136285Sbrian case DATALINK_HANGUP: 35236285Sbrian datalink_HangupDone(dl); 35336285Sbrian break; 35436285Sbrian case DATALINK_DIAL: 35549472Sbrian datalink_NewState(dl, DATALINK_CARRIER); 35636285Sbrian return datalink_UpdateSet(d, r, w, e, n); 35752488Sbrian case DATALINK_LOGOUT: 35852488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 35952488Sbrian physical_Offline(dl->physical); 36052488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 36152488Sbrian return datalink_UpdateSet(d, r, w, e, n); 36236285Sbrian case DATALINK_LOGIN: 36342390Sbrian dl->phone.alt = NULL; 36436285Sbrian datalink_LoginDone(dl); 36542905Sbrian return datalink_UpdateSet(d, r, w, e, n); 36636285Sbrian } 36736285Sbrian break; 36836285Sbrian case CHAT_FAILED: 36936285Sbrian /* Going down - script failed */ 37036285Sbrian log_Printf(LogWARN, "Chat script failed\n"); 37136285Sbrian switch(dl->state) { 37236285Sbrian case DATALINK_HANGUP: 37336285Sbrian datalink_HangupDone(dl); 37436285Sbrian break; 37536285Sbrian case DATALINK_DIAL: 37652488Sbrian case DATALINK_LOGOUT: 37736285Sbrian case DATALINK_LOGIN: 37836285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 37952488Sbrian physical_Offline(dl->physical); 38052488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 38136285Sbrian return datalink_UpdateSet(d, r, w, e, n); 38236285Sbrian } 38336285Sbrian break; 38436285Sbrian } 38536285Sbrian break; 38636285Sbrian 38736285Sbrian case DATALINK_READY: 38836285Sbrian case DATALINK_LCP: 38936285Sbrian case DATALINK_AUTH: 39038174Sbrian case DATALINK_CBCP: 39136285Sbrian case DATALINK_OPEN: 39243888Sbrian result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 39343888Sbrian descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 39436285Sbrian break; 39536285Sbrian } 39636285Sbrian return result; 39736285Sbrian} 39836285Sbrian 39936285Sbrianint 40036285Sbriandatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 40136285Sbrian{ 40236285Sbrian return physical_RemoveFromSet(dl->physical, r, w, e); 40336285Sbrian} 40436285Sbrian 40536285Sbrianstatic int 40636285Sbriandatalink_IsSet(struct descriptor *d, const fd_set *fdset) 40736285Sbrian{ 40836285Sbrian struct datalink *dl = descriptor2datalink(d); 40936285Sbrian 41036285Sbrian switch (dl->state) { 41136285Sbrian case DATALINK_CLOSED: 41236285Sbrian case DATALINK_OPENING: 41336285Sbrian break; 41436285Sbrian 41536285Sbrian case DATALINK_HANGUP: 41636285Sbrian case DATALINK_DIAL: 41752488Sbrian case DATALINK_LOGOUT: 41836285Sbrian case DATALINK_LOGIN: 41936285Sbrian return descriptor_IsSet(&dl->chat.desc, fdset); 42036285Sbrian 42136285Sbrian case DATALINK_READY: 42236285Sbrian case DATALINK_LCP: 42336285Sbrian case DATALINK_AUTH: 42438174Sbrian case DATALINK_CBCP: 42536285Sbrian case DATALINK_OPEN: 42643888Sbrian return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 42743888Sbrian descriptor_IsSet(&dl->physical->desc, fdset); 42836285Sbrian } 42936285Sbrian return 0; 43036285Sbrian} 43136285Sbrian 43236285Sbrianstatic void 43336285Sbriandatalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 43436285Sbrian{ 43536285Sbrian struct datalink *dl = descriptor2datalink(d); 43636285Sbrian 43736285Sbrian switch (dl->state) { 43836285Sbrian case DATALINK_CLOSED: 43936285Sbrian case DATALINK_OPENING: 44036285Sbrian break; 44136285Sbrian 44236285Sbrian case DATALINK_HANGUP: 44336285Sbrian case DATALINK_DIAL: 44452488Sbrian case DATALINK_LOGOUT: 44536285Sbrian case DATALINK_LOGIN: 44636285Sbrian descriptor_Read(&dl->chat.desc, bundle, fdset); 44736285Sbrian break; 44836285Sbrian 44936285Sbrian case DATALINK_READY: 45036285Sbrian case DATALINK_LCP: 45136285Sbrian case DATALINK_AUTH: 45238174Sbrian case DATALINK_CBCP: 45336285Sbrian case DATALINK_OPEN: 45443888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 45543888Sbrian descriptor_Read(&dl->chap.desc, bundle, fdset); 45643888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 45743888Sbrian descriptor_Read(&dl->physical->desc, bundle, fdset); 45836285Sbrian break; 45936285Sbrian } 46036285Sbrian} 46136285Sbrian 46237141Sbrianstatic int 46336285Sbriandatalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 46436285Sbrian{ 46536285Sbrian struct datalink *dl = descriptor2datalink(d); 46637141Sbrian int result = 0; 46736285Sbrian 46836285Sbrian switch (dl->state) { 46936285Sbrian case DATALINK_CLOSED: 47036285Sbrian case DATALINK_OPENING: 47136285Sbrian break; 47236285Sbrian 47336285Sbrian case DATALINK_HANGUP: 47436285Sbrian case DATALINK_DIAL: 47552488Sbrian case DATALINK_LOGOUT: 47636285Sbrian case DATALINK_LOGIN: 47737141Sbrian result = descriptor_Write(&dl->chat.desc, bundle, fdset); 47836285Sbrian break; 47936285Sbrian 48036285Sbrian case DATALINK_READY: 48136285Sbrian case DATALINK_LCP: 48236285Sbrian case DATALINK_AUTH: 48338174Sbrian case DATALINK_CBCP: 48436285Sbrian case DATALINK_OPEN: 48543888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 48643888Sbrian result += descriptor_Write(&dl->chap.desc, bundle, fdset); 48743888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 48843888Sbrian result += descriptor_Write(&dl->physical->desc, bundle, fdset); 48936285Sbrian break; 49036285Sbrian } 49137141Sbrian 49237141Sbrian return result; 49336285Sbrian} 49436285Sbrian 49536285Sbrianstatic void 49637007Sbriandatalink_ComeDown(struct datalink *dl, int how) 49736285Sbrian{ 49837007Sbrian if (how != CLOSE_NORMAL) { 49944468Sbrian dl->dial.tries = -1; 50036285Sbrian dl->reconnect_tries = 0; 50137012Sbrian if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 50237007Sbrian dl->stayonline = 1; 50336285Sbrian } 50436285Sbrian 50537012Sbrian if (dl->state >= DATALINK_READY && dl->stayonline) { 50637007Sbrian dl->stayonline = 0; 50747061Sbrian physical_StopDeviceTimer(dl->physical); 50837007Sbrian datalink_NewState(dl, DATALINK_READY); 50937007Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 51046686Sbrian physical_Offline(dl->physical); 51136285Sbrian if (dl->script.run && dl->state != DATALINK_OPENING) { 51252488Sbrian if (dl->state == DATALINK_LOGOUT) { 51352488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 51452488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, NULL); 51552488Sbrian } else { 51652488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 51752488Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.logout, NULL); 51852488Sbrian } 51936285Sbrian } else 52036285Sbrian datalink_HangupDone(dl); 52136285Sbrian } 52236285Sbrian} 52336285Sbrian 52436285Sbrianstatic void 52536285Sbriandatalink_LayerStart(void *v, struct fsm *fp) 52636285Sbrian{ 52736285Sbrian /* The given FSM is about to start up ! */ 52836285Sbrian struct datalink *dl = (struct datalink *)v; 52936285Sbrian 53036285Sbrian if (fp->proto == PROTO_LCP) 53136285Sbrian (*dl->parent->LayerStart)(dl->parent->object, fp); 53236285Sbrian} 53336285Sbrian 53436285Sbrianstatic void 53536285Sbriandatalink_LayerUp(void *v, struct fsm *fp) 53636285Sbrian{ 53736285Sbrian /* The given fsm is now up */ 53836285Sbrian struct datalink *dl = (struct datalink *)v; 53944106Sbrian struct lcp *lcp = &dl->physical->link.lcp; 54036285Sbrian 54136285Sbrian if (fp->proto == PROTO_LCP) { 54243693Sbrian datalink_GotAuthname(dl, ""); 54344106Sbrian lcp->auth_ineed = lcp->want_auth; 54444106Sbrian lcp->auth_iwait = lcp->his_auth; 54544106Sbrian if (lcp->his_auth || lcp->want_auth) { 54645350Sbrian if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 54736285Sbrian bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 54836285Sbrian log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 54944106Sbrian Auth2Nam(lcp->his_auth, lcp->his_authtype), 55044106Sbrian Auth2Nam(lcp->want_auth, lcp->want_authtype)); 55144106Sbrian if (lcp->his_auth == PROTO_PAP) 55243693Sbrian auth_StartReq(&dl->pap); 55344106Sbrian if (lcp->want_auth == PROTO_CHAP) 55443693Sbrian auth_StartReq(&dl->chap.auth); 55536285Sbrian } else 55636285Sbrian datalink_AuthOk(dl); 55736285Sbrian } 55836285Sbrian} 55936285Sbrian 56044094Sbrianstatic void 56144094Sbriandatalink_AuthReInit(struct datalink *dl) 56244094Sbrian{ 56344094Sbrian auth_StopTimer(&dl->pap); 56444094Sbrian auth_StopTimer(&dl->chap.auth); 56544094Sbrian chap_ReInit(&dl->chap); 56644094Sbrian} 56744094Sbrian 56836285Sbrianvoid 56943693Sbriandatalink_GotAuthname(struct datalink *dl, const char *name) 57036285Sbrian{ 57143693Sbrian strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 57243693Sbrian dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 57336285Sbrian} 57436285Sbrian 57536285Sbrianvoid 57638174Sbriandatalink_NCPUp(struct datalink *dl) 57736285Sbrian{ 57837320Sbrian int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 57936310Sbrian 58036285Sbrian if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 58136285Sbrian /* we've authenticated in multilink mode ! */ 58236285Sbrian switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 58336285Sbrian case MP_LINKSENT: 58436285Sbrian /* We've handed the link off to another ppp (well, we will soon) ! */ 58536285Sbrian return; 58636285Sbrian case MP_UP: 58736285Sbrian /* First link in the bundle */ 58838174Sbrian auth_Select(dl->bundle, dl->peer.authname); 58949434Sbrian bundle_CalculateBandwidth(dl->bundle); 59036285Sbrian /* fall through */ 59136285Sbrian case MP_ADDED: 59236285Sbrian /* We're in multilink mode ! */ 59336310Sbrian dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 59449434Sbrian bundle_CalculateBandwidth(dl->bundle); 59536285Sbrian break; 59636285Sbrian case MP_FAILED: 59736285Sbrian datalink_AuthNotOk(dl); 59836285Sbrian return; 59936285Sbrian } 60036285Sbrian } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 60136285Sbrian log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 60237160Sbrian datalink_NewState(dl, DATALINK_OPEN); 60349434Sbrian bundle_CalculateBandwidth(dl->bundle); 60437160Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 60536285Sbrian return; 60636285Sbrian } else { 60736285Sbrian dl->bundle->ncp.mp.peer = dl->peer; 60836285Sbrian ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 60938174Sbrian auth_Select(dl->bundle, dl->peer.authname); 61036285Sbrian } 61136285Sbrian 61237320Sbrian if (ccpok) { 61337320Sbrian fsm_Up(&dl->physical->link.ccp.fsm); 61437320Sbrian fsm_Open(&dl->physical->link.ccp.fsm); 61537320Sbrian } 61636285Sbrian datalink_NewState(dl, DATALINK_OPEN); 61736285Sbrian bundle_NewPhase(dl->bundle, PHASE_NETWORK); 61836285Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 61936285Sbrian} 62036285Sbrian 62136285Sbrianvoid 62238174Sbriandatalink_CBCPComplete(struct datalink *dl) 62338174Sbrian{ 62438174Sbrian datalink_NewState(dl, DATALINK_LCP); 62544094Sbrian datalink_AuthReInit(dl); 62638174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 62738174Sbrian} 62838174Sbrian 62938174Sbrianvoid 63038174Sbriandatalink_CBCPFailed(struct datalink *dl) 63138174Sbrian{ 63238174Sbrian cbcp_Down(&dl->cbcp); 63338174Sbrian datalink_CBCPComplete(dl); 63438174Sbrian} 63538174Sbrian 63638174Sbrianvoid 63738174Sbriandatalink_AuthOk(struct datalink *dl) 63838174Sbrian{ 63942600Sbrian if ((dl->physical->link.lcp.his_callback.opmask & 64042600Sbrian CALLBACK_BIT(CALLBACK_CBCP) || 64142600Sbrian dl->physical->link.lcp.want_callback.opmask & 64242600Sbrian CALLBACK_BIT(CALLBACK_CBCP)) && 64342600Sbrian !(dl->physical->link.lcp.want_callback.opmask & 64442600Sbrian CALLBACK_BIT(CALLBACK_AUTH))) { 64542600Sbrian /* We must have agreed CBCP if AUTH isn't there any more */ 64638174Sbrian datalink_NewState(dl, DATALINK_CBCP); 64738174Sbrian cbcp_Up(&dl->cbcp); 64838174Sbrian } else if (dl->physical->link.lcp.want_callback.opmask) { 64942600Sbrian /* It's not CBCP */ 65038174Sbrian log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 65138174Sbrian datalink_NewState(dl, DATALINK_LCP); 65244094Sbrian datalink_AuthReInit(dl); 65338174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 65438174Sbrian } else 65538174Sbrian switch (dl->physical->link.lcp.his_callback.opmask) { 65638174Sbrian case 0: 65738174Sbrian datalink_NCPUp(dl); 65838174Sbrian break; 65938174Sbrian 66038174Sbrian case CALLBACK_BIT(CALLBACK_AUTH): 66138174Sbrian auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 66238174Sbrian sizeof dl->cbcp.fsm.phone); 66338174Sbrian if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 66438174Sbrian log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 66538174Sbrian dl->peer.authname); 66638174Sbrian *dl->cbcp.fsm.phone = '\0'; 66738174Sbrian } else { 66838174Sbrian char *ptr = strchr(dl->cbcp.fsm.phone, ','); 66938174Sbrian if (ptr) 67038174Sbrian *ptr = '\0'; /* Call back on the first number */ 67138174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 67238174Sbrian dl->cbcp.fsm.phone); 67338174Sbrian dl->cbcp.required = 1; 67438174Sbrian } 67538174Sbrian dl->cbcp.fsm.delay = 0; 67638174Sbrian datalink_NewState(dl, DATALINK_LCP); 67744094Sbrian datalink_AuthReInit(dl); 67838174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 67938174Sbrian break; 68038174Sbrian 68138174Sbrian case CALLBACK_BIT(CALLBACK_E164): 68238174Sbrian strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 68338174Sbrian sizeof dl->cbcp.fsm.phone - 1); 68438174Sbrian dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 68538174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 68638174Sbrian dl->cbcp.fsm.phone); 68738174Sbrian dl->cbcp.required = 1; 68838174Sbrian dl->cbcp.fsm.delay = 0; 68938174Sbrian datalink_NewState(dl, DATALINK_LCP); 69044094Sbrian datalink_AuthReInit(dl); 69138174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 69238174Sbrian break; 69338174Sbrian 69438174Sbrian default: 69538174Sbrian log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 69638174Sbrian dl->name); 69738174Sbrian datalink_NewState(dl, DATALINK_LCP); 69844094Sbrian datalink_AuthReInit(dl); 69938174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 70038174Sbrian break; 70138174Sbrian } 70238174Sbrian} 70338174Sbrian 70438174Sbrianvoid 70536285Sbriandatalink_AuthNotOk(struct datalink *dl) 70636285Sbrian{ 70736285Sbrian datalink_NewState(dl, DATALINK_LCP); 70844094Sbrian datalink_AuthReInit(dl); 70936285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 71036285Sbrian} 71136285Sbrian 71236285Sbrianstatic void 71336285Sbriandatalink_LayerDown(void *v, struct fsm *fp) 71436285Sbrian{ 71536285Sbrian /* The given FSM has been told to come down */ 71636285Sbrian struct datalink *dl = (struct datalink *)v; 71736285Sbrian 71836285Sbrian if (fp->proto == PROTO_LCP) { 71936285Sbrian switch (dl->state) { 72036285Sbrian case DATALINK_OPEN: 72136285Sbrian peerid_Init(&dl->peer); 72237060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 72336928Sbrian datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 72436285Sbrian (*dl->parent->LayerDown)(dl->parent->object, fp); 72538174Sbrian /* fall through (just in case) */ 72636285Sbrian 72738174Sbrian case DATALINK_CBCP: 72838174Sbrian if (!dl->cbcp.required) 72938174Sbrian cbcp_Down(&dl->cbcp); 73038174Sbrian /* fall through (just in case) */ 73138174Sbrian 73236285Sbrian case DATALINK_AUTH: 73336285Sbrian timer_Stop(&dl->pap.authtimer); 73436285Sbrian timer_Stop(&dl->chap.auth.authtimer); 73536285Sbrian } 73636285Sbrian datalink_NewState(dl, DATALINK_LCP); 73744094Sbrian datalink_AuthReInit(dl); 73836285Sbrian } 73936285Sbrian} 74036285Sbrian 74136285Sbrianstatic void 74236285Sbriandatalink_LayerFinish(void *v, struct fsm *fp) 74336285Sbrian{ 74436285Sbrian /* The given fsm is now down */ 74536285Sbrian struct datalink *dl = (struct datalink *)v; 74636285Sbrian 74736285Sbrian if (fp->proto == PROTO_LCP) { 74837060Sbrian fsm2initial(fp); 74936285Sbrian (*dl->parent->LayerFinish)(dl->parent->object, fp); 75037007Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 75136285Sbrian } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 75236285Sbrian fsm_Open(fp); /* CCP goes to ST_STOPPED */ 75336285Sbrian} 75436285Sbrian 75536285Sbrianstruct datalink * 75636285Sbriandatalink_Create(const char *name, struct bundle *bundle, int type) 75736285Sbrian{ 75836285Sbrian struct datalink *dl; 75936285Sbrian 76036285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 76136285Sbrian if (dl == NULL) 76236285Sbrian return dl; 76336285Sbrian 76436285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 76536285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 76636285Sbrian dl->desc.IsSet = datalink_IsSet; 76736285Sbrian dl->desc.Read = datalink_Read; 76836285Sbrian dl->desc.Write = datalink_Write; 76936285Sbrian 77036285Sbrian dl->state = DATALINK_CLOSED; 77136285Sbrian 77236285Sbrian *dl->cfg.script.dial = '\0'; 77336285Sbrian *dl->cfg.script.login = '\0'; 77452488Sbrian *dl->cfg.script.logout = '\0'; 77536285Sbrian *dl->cfg.script.hangup = '\0'; 77636285Sbrian *dl->cfg.phone.list = '\0'; 77736285Sbrian *dl->phone.list = '\0'; 77836285Sbrian dl->phone.next = NULL; 77936285Sbrian dl->phone.alt = NULL; 78036285Sbrian dl->phone.chosen = "N/A"; 78137007Sbrian dl->stayonline = 0; 78236285Sbrian dl->script.run = 1; 78336285Sbrian dl->script.packetmode = 1; 78436285Sbrian mp_linkInit(&dl->mp); 78536285Sbrian 78636285Sbrian dl->bundle = bundle; 78736285Sbrian dl->next = NULL; 78836285Sbrian 78944468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 79036285Sbrian 79144468Sbrian dl->dial.tries = 0; 79236285Sbrian dl->cfg.dial.max = 1; 79336285Sbrian dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 79436285Sbrian dl->cfg.dial.timeout = DIAL_TIMEOUT; 79544468Sbrian dl->cfg.dial.inc = 0; 79644468Sbrian dl->cfg.dial.maxinc = 10; 79736285Sbrian 79836285Sbrian dl->reconnect_tries = 0; 79936285Sbrian dl->cfg.reconnect.max = 0; 80036285Sbrian dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 80136285Sbrian 80238174Sbrian dl->cfg.callback.opmask = 0; 80338174Sbrian dl->cfg.cbcp.delay = 0; 80438174Sbrian *dl->cfg.cbcp.phone = '\0'; 80538174Sbrian dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 80638174Sbrian 80736285Sbrian dl->name = strdup(name); 80836285Sbrian peerid_Init(&dl->peer); 80936285Sbrian dl->parent = &bundle->fsm; 81036285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 81136285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 81236285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 81336285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 81436285Sbrian dl->fsmp.object = dl; 81536285Sbrian 81646686Sbrian if ((dl->physical = physical_Create(dl, type)) == NULL) { 81736285Sbrian free(dl->name); 81836285Sbrian free(dl); 81936285Sbrian return NULL; 82036285Sbrian } 82143693Sbrian 82243693Sbrian pap_Init(&dl->pap, dl->physical); 82343693Sbrian chap_Init(&dl->chap, dl->physical); 82438174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 82536285Sbrian 82652488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 82752488Sbrian chat_Init(&dl->chat, dl->physical, NULL, NULL); 82852488Sbrian 82936285Sbrian log_Printf(LogPHASE, "%s: Created in %s state\n", 83036285Sbrian dl->name, datalink_State(dl)); 83136285Sbrian 83236285Sbrian return dl; 83336285Sbrian} 83436285Sbrian 83536285Sbrianstruct datalink * 83636285Sbriandatalink_Clone(struct datalink *odl, const char *name) 83736285Sbrian{ 83836285Sbrian struct datalink *dl; 83936285Sbrian 84036285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 84136285Sbrian if (dl == NULL) 84236285Sbrian return dl; 84336285Sbrian 84436285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 84536285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 84636285Sbrian dl->desc.IsSet = datalink_IsSet; 84736285Sbrian dl->desc.Read = datalink_Read; 84836285Sbrian dl->desc.Write = datalink_Write; 84936285Sbrian 85036285Sbrian dl->state = DATALINK_CLOSED; 85136285Sbrian 85236285Sbrian memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 85336285Sbrian mp_linkInit(&dl->mp); 85436285Sbrian *dl->phone.list = '\0'; 85536285Sbrian dl->phone.next = NULL; 85636285Sbrian dl->phone.alt = NULL; 85736285Sbrian dl->phone.chosen = "N/A"; 85836285Sbrian dl->bundle = odl->bundle; 85936285Sbrian dl->next = NULL; 86044468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 86144468Sbrian dl->dial.tries = 0; 86236285Sbrian dl->reconnect_tries = 0; 86336285Sbrian dl->name = strdup(name); 86436285Sbrian peerid_Init(&dl->peer); 86536285Sbrian dl->parent = odl->parent; 86636285Sbrian memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 86736285Sbrian dl->fsmp.object = dl; 86836285Sbrian 86946686Sbrian if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { 87036285Sbrian free(dl->name); 87136285Sbrian free(dl); 87236285Sbrian return NULL; 87336285Sbrian } 87443693Sbrian pap_Init(&dl->pap, dl->physical); 87544305Sbrian dl->pap.cfg = odl->pap.cfg; 87643693Sbrian 87743693Sbrian chap_Init(&dl->chap, dl->physical); 87844305Sbrian dl->chap.auth.cfg = odl->chap.auth.cfg; 87943693Sbrian 88036285Sbrian memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 88136285Sbrian memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 88236285Sbrian sizeof dl->physical->link.lcp.cfg); 88336285Sbrian memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 88436285Sbrian sizeof dl->physical->link.ccp.cfg); 88536285Sbrian memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 88636285Sbrian sizeof dl->physical->async.cfg); 88736285Sbrian 88838174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 88936285Sbrian 89052488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 89152488Sbrian chat_Init(&dl->chat, dl->physical, NULL, NULL); 89252488Sbrian 89336285Sbrian log_Printf(LogPHASE, "%s: Cloned in %s state\n", 89436285Sbrian dl->name, datalink_State(dl)); 89536285Sbrian 89636285Sbrian return dl; 89736285Sbrian} 89836285Sbrian 89936285Sbrianstruct datalink * 90036285Sbriandatalink_Destroy(struct datalink *dl) 90136285Sbrian{ 90236285Sbrian struct datalink *result; 90336285Sbrian 90436285Sbrian if (dl->state != DATALINK_CLOSED) { 90536285Sbrian log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 90636285Sbrian datalink_State(dl)); 90736285Sbrian switch (dl->state) { 90836285Sbrian case DATALINK_HANGUP: 90936285Sbrian case DATALINK_DIAL: 91036285Sbrian case DATALINK_LOGIN: 91136285Sbrian chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 91236285Sbrian break; 91336285Sbrian } 91436285Sbrian } 91536285Sbrian 91644468Sbrian timer_Stop(&dl->dial.timer); 91736285Sbrian result = dl->next; 91846686Sbrian physical_Destroy(dl->physical); 91936285Sbrian free(dl->name); 92036285Sbrian free(dl); 92136285Sbrian 92236285Sbrian return result; 92336285Sbrian} 92436285Sbrian 92536285Sbrianvoid 92636285Sbriandatalink_Up(struct datalink *dl, int runscripts, int packetmode) 92736285Sbrian{ 92836285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 92936285Sbrian /* Ignore scripts */ 93036285Sbrian runscripts = 0; 93136285Sbrian 93236285Sbrian switch (dl->state) { 93336285Sbrian case DATALINK_CLOSED: 93436285Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 93536285Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 93636285Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 93736285Sbrian datalink_NewState(dl, DATALINK_OPENING); 93836285Sbrian dl->reconnect_tries = 93936285Sbrian dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 94044468Sbrian dl->dial.tries = dl->cfg.dial.max; 94136285Sbrian dl->script.run = runscripts; 94236285Sbrian dl->script.packetmode = packetmode; 94336285Sbrian break; 94436285Sbrian 94536285Sbrian case DATALINK_OPENING: 94636285Sbrian if (!dl->script.run && runscripts) 94736285Sbrian dl->script.run = 1; 94836285Sbrian /* fall through */ 94936285Sbrian 95036285Sbrian case DATALINK_DIAL: 95136285Sbrian case DATALINK_LOGIN: 95236285Sbrian case DATALINK_READY: 95336285Sbrian if (!dl->script.packetmode && packetmode) { 95436285Sbrian dl->script.packetmode = 1; 95536285Sbrian if (dl->state == DATALINK_READY) 95636285Sbrian datalink_LoginDone(dl); 95736285Sbrian } 95836285Sbrian break; 95936285Sbrian } 96036285Sbrian} 96136285Sbrian 96236285Sbrianvoid 96337007Sbriandatalink_Close(struct datalink *dl, int how) 96436285Sbrian{ 96536285Sbrian /* Please close */ 96636285Sbrian switch (dl->state) { 96736285Sbrian case DATALINK_OPEN: 96836285Sbrian peerid_Init(&dl->peer); 96937060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 97036285Sbrian /* fall through */ 97136285Sbrian 97238174Sbrian case DATALINK_CBCP: 97336285Sbrian case DATALINK_AUTH: 97436285Sbrian case DATALINK_LCP: 97544094Sbrian datalink_AuthReInit(dl); 97636285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 97737007Sbrian if (how != CLOSE_NORMAL) { 97844468Sbrian dl->dial.tries = -1; 97936285Sbrian dl->reconnect_tries = 0; 98037007Sbrian if (how == CLOSE_LCP) 98137007Sbrian dl->stayonline = 1; 98236285Sbrian } 98352029Sbrian break; 98436285Sbrian 98536285Sbrian default: 98637007Sbrian datalink_ComeDown(dl, how); 98736285Sbrian } 98836285Sbrian} 98936285Sbrian 99036285Sbrianvoid 99137007Sbriandatalink_Down(struct datalink *dl, int how) 99236285Sbrian{ 99336285Sbrian /* Carrier is lost */ 99436285Sbrian switch (dl->state) { 99536285Sbrian case DATALINK_OPEN: 99636285Sbrian peerid_Init(&dl->peer); 99737060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 99836285Sbrian /* fall through */ 99936285Sbrian 100038174Sbrian case DATALINK_CBCP: 100136285Sbrian case DATALINK_AUTH: 100236285Sbrian case DATALINK_LCP: 100337060Sbrian fsm2initial(&dl->physical->link.lcp.fsm); 100436285Sbrian /* fall through */ 100536285Sbrian 100636285Sbrian default: 100737007Sbrian datalink_ComeDown(dl, how); 100836285Sbrian } 100936285Sbrian} 101036285Sbrian 101136285Sbrianvoid 101236285Sbriandatalink_StayDown(struct datalink *dl) 101336285Sbrian{ 101436285Sbrian dl->reconnect_tries = 0; 101536285Sbrian} 101636285Sbrian 101737007Sbrianvoid 101837007Sbriandatalink_DontHangup(struct datalink *dl) 101937007Sbrian{ 102037012Sbrian if (dl->state >= DATALINK_LCP) 102137012Sbrian dl->stayonline = 1; 102237007Sbrian} 102337007Sbrian 102436285Sbrianint 102536285Sbriandatalink_Show(struct cmdargs const *arg) 102636285Sbrian{ 102736285Sbrian prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 102838174Sbrian prompt_Printf(arg->prompt, " State: %s\n", 102936285Sbrian datalink_State(arg->cx)); 103038174Sbrian prompt_Printf(arg->prompt, " Peer name: "); 103136285Sbrian if (*arg->cx->peer.authname) 103236285Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 103336285Sbrian else if (arg->cx->state == DATALINK_OPEN) 103436285Sbrian prompt_Printf(arg->prompt, "None requested\n"); 103536285Sbrian else 103636285Sbrian prompt_Printf(arg->prompt, "N/A\n"); 103738174Sbrian prompt_Printf(arg->prompt, " Discriminator: %s\n", 103836285Sbrian mp_Enddisc(arg->cx->peer.enddisc.class, 103936285Sbrian arg->cx->peer.enddisc.address, 104036285Sbrian arg->cx->peer.enddisc.len)); 104136285Sbrian 104236285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 104338174Sbrian prompt_Printf(arg->prompt, " Phone List: %s\n", 104436285Sbrian arg->cx->cfg.phone.list); 104536285Sbrian if (arg->cx->cfg.dial.max) 104638174Sbrian prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 104736285Sbrian arg->cx->cfg.dial.max); 104836285Sbrian else 104938174Sbrian prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 105044261Sbrian if (arg->cx->cfg.dial.next_timeout >= 0) 105136285Sbrian prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 105236285Sbrian else 105336285Sbrian prompt_Printf(arg->prompt, "random/"); 105444261Sbrian if (arg->cx->cfg.dial.timeout >= 0) 105536285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 105636285Sbrian else 105736285Sbrian prompt_Printf(arg->prompt, "random\n"); 105838174Sbrian prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 105936285Sbrian arg->cx->cfg.reconnect.max); 106036285Sbrian if (arg->cx->cfg.reconnect.timeout > 0) 106136285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 106236285Sbrian else 106336285Sbrian prompt_Printf(arg->prompt, "random\n"); 106438174Sbrian prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 106538174Sbrian PHYS_DIRECT ? "accepted: " : "requested:"); 106638174Sbrian if (!arg->cx->cfg.callback.opmask) 106738174Sbrian prompt_Printf(arg->prompt, "none\n"); 106838174Sbrian else { 106938174Sbrian int comma = 0; 107038174Sbrian 107138174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 107238174Sbrian prompt_Printf(arg->prompt, "none"); 107338174Sbrian comma = 1; 107438174Sbrian } 107538174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 107638174Sbrian prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 107738174Sbrian comma = 1; 107838174Sbrian } 107938174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 108038174Sbrian prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 108138174Sbrian if (arg->cx->physical->type != PHYS_DIRECT) 108238174Sbrian prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 108338174Sbrian comma = 1; 108438174Sbrian } 108538174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 108638174Sbrian prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 108738174Sbrian prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 108838174Sbrian arg->cx->cfg.cbcp.delay); 108940483Sbrian prompt_Printf(arg->prompt, " phone: "); 109040483Sbrian if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 109140483Sbrian if (arg->cx->physical->type & PHYS_DIRECT) 109240483Sbrian prompt_Printf(arg->prompt, "Caller decides\n"); 109340483Sbrian else 109440483Sbrian prompt_Printf(arg->prompt, "Dialback server decides\n"); 109540483Sbrian } else 109640483Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 109738174Sbrian prompt_Printf(arg->prompt, " timeout: %lds\n", 109838174Sbrian arg->cx->cfg.cbcp.fsmretry); 109938174Sbrian } else 110038174Sbrian prompt_Printf(arg->prompt, "\n"); 110138174Sbrian } 110238174Sbrian 110338174Sbrian prompt_Printf(arg->prompt, " Dial Script: %s\n", 110436285Sbrian arg->cx->cfg.script.dial); 110538174Sbrian prompt_Printf(arg->prompt, " Login Script: %s\n", 110636285Sbrian arg->cx->cfg.script.login); 110752488Sbrian prompt_Printf(arg->prompt, " Logout Script: %s\n", 110852488Sbrian arg->cx->cfg.script.logout); 110938174Sbrian prompt_Printf(arg->prompt, " Hangup Script: %s\n", 111036285Sbrian arg->cx->cfg.script.hangup); 111136285Sbrian return 0; 111236285Sbrian} 111336285Sbrian 111436285Sbrianint 111536285Sbriandatalink_SetReconnect(struct cmdargs const *arg) 111636285Sbrian{ 111736285Sbrian if (arg->argc == arg->argn+2) { 111836285Sbrian arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 111936285Sbrian arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 112036285Sbrian return 0; 112136285Sbrian } 112236285Sbrian return -1; 112336285Sbrian} 112436285Sbrian 112536285Sbrianint 112636285Sbriandatalink_SetRedial(struct cmdargs const *arg) 112736285Sbrian{ 112844468Sbrian const char *sep, *osep; 112944468Sbrian int timeout, inc, maxinc, tries; 113036285Sbrian 113136285Sbrian if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 113236285Sbrian if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 113336285Sbrian (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 113436285Sbrian arg->cx->cfg.dial.timeout = -1; 113536285Sbrian randinit(); 113636285Sbrian } else { 113736285Sbrian timeout = atoi(arg->argv[arg->argn]); 113836285Sbrian 113936285Sbrian if (timeout >= 0) 114036285Sbrian arg->cx->cfg.dial.timeout = timeout; 114136285Sbrian else { 114236285Sbrian log_Printf(LogWARN, "Invalid redial timeout\n"); 114336285Sbrian return -1; 114436285Sbrian } 114536285Sbrian } 114636285Sbrian 114744468Sbrian sep = strchr(arg->argv[arg->argn], '+'); 114844468Sbrian if (sep) { 114944468Sbrian inc = atoi(++sep); 115044468Sbrian osep = sep; 115144468Sbrian if (inc >= 0) 115244468Sbrian arg->cx->cfg.dial.inc = inc; 115344468Sbrian else { 115444468Sbrian log_Printf(LogWARN, "Invalid timeout increment\n"); 115544468Sbrian return -1; 115644468Sbrian } 115744468Sbrian sep = strchr(sep, '-'); 115844468Sbrian if (sep) { 115944468Sbrian maxinc = atoi(++sep); 116044468Sbrian if (maxinc >= 0) 116144468Sbrian arg->cx->cfg.dial.maxinc = maxinc; 116244468Sbrian else { 116344468Sbrian log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 116444468Sbrian return -1; 116544468Sbrian } 116644468Sbrian } else { 116744468Sbrian /* Default timeout increment */ 116844468Sbrian arg->cx->cfg.dial.maxinc = 10; 116944468Sbrian sep = osep; 117044468Sbrian } 117144468Sbrian } else { 117244468Sbrian /* Default timeout increment & max increment */ 117344468Sbrian arg->cx->cfg.dial.inc = 0; 117444468Sbrian arg->cx->cfg.dial.maxinc = 10; 117544468Sbrian sep = arg->argv[arg->argn]; 117644468Sbrian } 117744468Sbrian 117844468Sbrian sep = strchr(sep, '.'); 117944468Sbrian if (sep) { 118044468Sbrian if (strcasecmp(++sep, "random") == 0) { 118136285Sbrian arg->cx->cfg.dial.next_timeout = -1; 118236285Sbrian randinit(); 118336285Sbrian } else { 118444468Sbrian timeout = atoi(sep); 118536285Sbrian if (timeout >= 0) 118636285Sbrian arg->cx->cfg.dial.next_timeout = timeout; 118736285Sbrian else { 118836285Sbrian log_Printf(LogWARN, "Invalid next redial timeout\n"); 118936285Sbrian return -1; 119036285Sbrian } 119136285Sbrian } 119236285Sbrian } else 119336285Sbrian /* Default next timeout */ 119436285Sbrian arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 119536285Sbrian 119636285Sbrian if (arg->argc == arg->argn+2) { 119736285Sbrian tries = atoi(arg->argv[arg->argn+1]); 119836285Sbrian 119936285Sbrian if (tries >= 0) { 120036285Sbrian arg->cx->cfg.dial.max = tries; 120136285Sbrian } else { 120236285Sbrian log_Printf(LogWARN, "Invalid retry value\n"); 120336285Sbrian return 1; 120436285Sbrian } 120536285Sbrian } 120636285Sbrian return 0; 120736285Sbrian } 120844468Sbrian 120936285Sbrian return -1; 121036285Sbrian} 121136285Sbrian 121236285Sbrianstatic const char *states[] = { 121336285Sbrian "closed", 121436285Sbrian "opening", 121536285Sbrian "hangup", 121636285Sbrian "dial", 121749472Sbrian "carrier", 121852488Sbrian "logout", 121936285Sbrian "login", 122036285Sbrian "ready", 122136285Sbrian "lcp", 122236285Sbrian "auth", 122338174Sbrian "cbcp", 122436285Sbrian "open" 122536285Sbrian}; 122636285Sbrian 122736285Sbrianconst char * 122836285Sbriandatalink_State(struct datalink *dl) 122936285Sbrian{ 123036285Sbrian if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 123136285Sbrian return "unknown"; 123236285Sbrian return states[dl->state]; 123336285Sbrian} 123436285Sbrian 123536285Sbrianstatic void 123636285Sbriandatalink_NewState(struct datalink *dl, int state) 123736285Sbrian{ 123836285Sbrian if (state != dl->state) { 123936285Sbrian if (state >= 0 && state < sizeof states / sizeof states[0]) { 124036285Sbrian log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 124136285Sbrian states[state]); 124236285Sbrian dl->state = state; 124336285Sbrian } else 124436285Sbrian log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 124536285Sbrian } 124636285Sbrian} 124736285Sbrian 124836285Sbrianstruct datalink * 124936285Sbrianiov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 125052942Sbrian int fd, int *auxfd, int *nauxfd) 125136285Sbrian{ 125236285Sbrian struct datalink *dl, *cdl; 125344305Sbrian struct fsm_retry copy; 125436285Sbrian char *oname; 125536285Sbrian 125636285Sbrian dl = (struct datalink *)iov[(*niov)++].iov_base; 125736285Sbrian dl->name = iov[*niov].iov_base; 125836285Sbrian 125936285Sbrian if (dl->name[DATALINK_MAXNAME-1]) { 126036285Sbrian dl->name[DATALINK_MAXNAME-1] = '\0'; 126136285Sbrian if (strlen(dl->name) == DATALINK_MAXNAME - 1) 126236285Sbrian log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 126336285Sbrian } 126436285Sbrian 126536285Sbrian /* Make sure the name is unique ! */ 126636285Sbrian oname = NULL; 126736285Sbrian do { 126836285Sbrian for (cdl = bundle->links; cdl; cdl = cdl->next) 126936285Sbrian if (!strcasecmp(dl->name, cdl->name)) { 127036285Sbrian if (oname) 127136285Sbrian free(datalink_NextName(dl)); 127236285Sbrian else 127336285Sbrian oname = datalink_NextName(dl); 127436285Sbrian break; /* Keep renaming 'till we have no conflicts */ 127536285Sbrian } 127636285Sbrian } while (cdl); 127736285Sbrian 127836285Sbrian if (oname) { 127936285Sbrian log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 128036285Sbrian free(oname); 128136285Sbrian } else { 128236285Sbrian dl->name = strdup(dl->name); 128336285Sbrian free(iov[*niov].iov_base); 128436285Sbrian } 128536285Sbrian (*niov)++; 128636285Sbrian 128736285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 128836285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 128936285Sbrian dl->desc.IsSet = datalink_IsSet; 129036285Sbrian dl->desc.Read = datalink_Read; 129136285Sbrian dl->desc.Write = datalink_Write; 129236285Sbrian 129336285Sbrian mp_linkInit(&dl->mp); 129436285Sbrian *dl->phone.list = '\0'; 129536285Sbrian dl->phone.next = NULL; 129636285Sbrian dl->phone.alt = NULL; 129736285Sbrian dl->phone.chosen = "N/A"; 129836285Sbrian 129936285Sbrian dl->bundle = bundle; 130036285Sbrian dl->next = NULL; 130144468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 130244468Sbrian dl->dial.tries = 0; 130336285Sbrian dl->reconnect_tries = 0; 130436285Sbrian dl->parent = &bundle->fsm; 130536285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 130636285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 130736285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 130836285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 130936285Sbrian dl->fsmp.object = dl; 131036285Sbrian 131152942Sbrian dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); 131236285Sbrian 131336285Sbrian if (!dl->physical) { 131436285Sbrian free(dl->name); 131536285Sbrian free(dl); 131636285Sbrian dl = NULL; 131736285Sbrian } else { 131844305Sbrian copy = dl->pap.cfg.fsm; 131943693Sbrian pap_Init(&dl->pap, dl->physical); 132044305Sbrian dl->pap.cfg.fsm = copy; 132143693Sbrian 132244305Sbrian copy = dl->chap.auth.cfg.fsm; 132343693Sbrian chap_Init(&dl->chap, dl->physical); 132444305Sbrian dl->chap.auth.cfg.fsm = copy; 132543693Sbrian 132638174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 132736285Sbrian 132852488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 132952488Sbrian chat_Init(&dl->chat, dl->physical, NULL, NULL); 133052488Sbrian 133136285Sbrian log_Printf(LogPHASE, "%s: Transferred in %s state\n", 133236285Sbrian dl->name, datalink_State(dl)); 133336285Sbrian } 133436285Sbrian 133536285Sbrian return dl; 133636285Sbrian} 133736285Sbrian 133836285Sbrianint 133936450Sbriandatalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 134052942Sbrian int *auxfd, int *nauxfd, pid_t newpid) 134136285Sbrian{ 134236285Sbrian /* If `dl' is NULL, we're allocating before a Fromiov() */ 134336285Sbrian int link_fd; 134436285Sbrian 134536285Sbrian if (dl) { 134644468Sbrian timer_Stop(&dl->dial.timer); 134738174Sbrian /* The following is purely for the sake of paranoia */ 134838174Sbrian cbcp_Down(&dl->cbcp); 134936285Sbrian timer_Stop(&dl->pap.authtimer); 135036285Sbrian timer_Stop(&dl->chap.auth.authtimer); 135136285Sbrian } 135236285Sbrian 135336285Sbrian if (*niov >= maxiov - 1) { 135436285Sbrian log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 135536285Sbrian if (dl) { 135636285Sbrian free(dl->name); 135736285Sbrian free(dl); 135836285Sbrian } 135936285Sbrian return -1; 136036285Sbrian } 136136285Sbrian 136236285Sbrian iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 136336285Sbrian iov[(*niov)++].iov_len = sizeof *dl; 136436285Sbrian iov[*niov].iov_base = 136536285Sbrian dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 136636285Sbrian iov[(*niov)++].iov_len = DATALINK_MAXNAME; 136736285Sbrian 136852942Sbrian link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, 136952942Sbrian nauxfd, newpid); 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; 141436465Sbrian if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 141536285Sbrian datalink_Up(dl, 1, 1); 141636285Sbrian return 1; 141736285Sbrian} 141844468Sbrian 141944468Sbrianint 142044468Sbriandatalink_GetDialTimeout(struct datalink *dl) 142144468Sbrian{ 142244468Sbrian int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 142344468Sbrian 142444468Sbrian if (dl->dial.incs < dl->cfg.dial.maxinc) 142544468Sbrian dl->dial.incs++; 142644468Sbrian 142744468Sbrian return result; 142844468Sbrian} 1429