datalink.c revision 54914
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 54914 1999-12-20 20:30:02Z 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 12354055Sbrian chat_Finish(&dl->chat); 12446686Sbrian physical_Close(dl->physical); 12536285Sbrian dl->phone.chosen = "N/A"; 12636285Sbrian 12738174Sbrian if (dl->cbcp.required) { 12838174Sbrian log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 12938174Sbrian dl->cfg.callback.opmask = 0; 13038174Sbrian strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 13138174Sbrian sizeof dl->cfg.phone.list - 1); 13238174Sbrian dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 13338174Sbrian dl->phone.alt = dl->phone.next = NULL; 13438174Sbrian dl->reconnect_tries = dl->cfg.reconnect.max; 13544468Sbrian dl->dial.tries = dl->cfg.dial.max; 13644468Sbrian dl->dial.incs = 0; 13738174Sbrian dl->script.run = 1; 13838174Sbrian dl->script.packetmode = 1; 13938174Sbrian if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 14038174Sbrian log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 14138174Sbrian bundle_LinksRemoved(dl->bundle); 14244468Sbrian /* if dial.timeout is < 0 (random), we don't override fsm.delay */ 14338174Sbrian if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 14438174Sbrian dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 14538174Sbrian datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 14638174Sbrian cbcp_Down(&dl->cbcp); 14738174Sbrian datalink_NewState(dl, DATALINK_OPENING); 14852412Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 14952412Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 15045385Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 15138174Sbrian } else if (dl->bundle->CleaningUp || 15236285Sbrian (dl->physical->type == PHYS_DIRECT) || 15344468Sbrian ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15436465Sbrian !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 15536285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 15644468Sbrian dl->dial.tries = -1; 15744468Sbrian dl->dial.incs = 0; 15836285Sbrian dl->reconnect_tries = 0; 15936285Sbrian bundle_LinkClosed(dl->bundle, dl); 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{ 20654055Sbrian chat_Finish(&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); 21754914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 21854914Sbrian log_Printf(LogWARN, "Invalid logout script\n"); 21936285Sbrian } else { 22047061Sbrian physical_StopDeviceTimer(dl->physical); 22136285Sbrian if (dl->physical->type == PHYS_DEDICATED) 22236285Sbrian /* force a redial timeout */ 22346686Sbrian physical_Close(dl->physical); 22436285Sbrian datalink_HangupDone(dl); 22536285Sbrian } 22636285Sbrian } else { 22744468Sbrian dl->dial.tries = -1; 22844468Sbrian dl->dial.incs = 0; 22936285Sbrian 23036285Sbrian hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 23136285Sbrian async_Init(&dl->physical->async); 23236285Sbrian 23336285Sbrian lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 23436285Sbrian 0 : dl->physical->link.lcp.cfg.openmode); 23536285Sbrian ccp_Setup(&dl->physical->link.ccp); 23636285Sbrian 23736285Sbrian datalink_NewState(dl, DATALINK_LCP); 23836285Sbrian fsm_Up(&dl->physical->link.lcp.fsm); 23936285Sbrian fsm_Open(&dl->physical->link.lcp.fsm); 24036285Sbrian } 24136285Sbrian} 24236285Sbrian 24336285Sbrianstatic int 24436285Sbriandatalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 24536285Sbrian int *n) 24636285Sbrian{ 24736285Sbrian struct datalink *dl = descriptor2datalink(d); 24836285Sbrian int result; 24936285Sbrian 25036285Sbrian result = 0; 25136285Sbrian switch (dl->state) { 25236285Sbrian case DATALINK_CLOSED: 25353830Sbrian if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND| 25453830Sbrian PHYS_FOREGROUND|PHYS_DDIAL)) && 25547863Sbrian !dl->bundle->CleaningUp) 25636285Sbrian /* 25736465Sbrian * Our first time in - DEDICATED & DDIAL never come down, and 25853830Sbrian * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter 25953830Sbrian * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up() 26053830Sbrian * and fall through. 26136285Sbrian */ 26236285Sbrian datalink_Up(dl, 1, 1); 26336285Sbrian else 26436285Sbrian break; 26536285Sbrian /* fall through */ 26636285Sbrian 26736285Sbrian case DATALINK_OPENING: 26844468Sbrian if (dl->dial.timer.state != TIMER_RUNNING) { 26944468Sbrian if (--dl->dial.tries < 0) 27044468Sbrian dl->dial.tries = 0; 27146686Sbrian if (physical_Open(dl->physical, dl->bundle) >= 0) { 27238200Sbrian log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 27338200Sbrian "Type `~?' for help\r\n", dl->name, 27438200Sbrian dl->physical->name.full); 27536285Sbrian if (dl->script.run) { 27636285Sbrian datalink_NewState(dl, DATALINK_DIAL); 27754914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.dial, 27854914Sbrian *dl->cfg.script.dial ? 27954914Sbrian datalink_ChoosePhoneNumber(dl) : "")) 28054914Sbrian log_Printf(LogWARN, "Invalid dial script\n"); 28136465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 28236285Sbrian dl->cfg.dial.max) 28336285Sbrian log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 28444468Sbrian dl->name, dl->cfg.dial.max - dl->dial.tries, 28536285Sbrian dl->cfg.dial.max); 28636285Sbrian } else 28751978Sbrian datalink_NewState(dl, DATALINK_CARRIER); 28841830Sbrian return datalink_UpdateSet(d, r, w, e, n); 28936285Sbrian } else { 29036465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 29136285Sbrian dl->cfg.dial.max) 29246686Sbrian log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", 29344468Sbrian dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 29436285Sbrian else 29546686Sbrian log_Printf(LogCHAT, "Failed to open device\n"); 29636285Sbrian 29736285Sbrian if (dl->bundle->CleaningUp || 29836465Sbrian (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 29944468Sbrian dl->cfg.dial.max && dl->dial.tries == 0)) { 30036285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 30136285Sbrian dl->reconnect_tries = 0; 30244468Sbrian dl->dial.tries = -1; 30338200Sbrian log_WritePrompts(dl, "Failed to open %s\n", 30438200Sbrian dl->physical->name.full); 30536285Sbrian bundle_LinkClosed(dl->bundle, dl); 30636285Sbrian } 30738200Sbrian if (!dl->bundle->CleaningUp) { 30844468Sbrian int timeout; 30944468Sbrian 31044468Sbrian timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 31138200Sbrian log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 31244261Sbrian dl->physical->name.full, timeout); 31338200Sbrian } 31436285Sbrian } 31536285Sbrian } 31636285Sbrian break; 31736285Sbrian 31849472Sbrian case DATALINK_CARRIER: 31949472Sbrian /* Wait for carrier on the device */ 32049472Sbrian switch (physical_AwaitCarrier(dl->physical)) { 32149472Sbrian case CARRIER_PENDING: 32249472Sbrian log_Printf(LogDEBUG, "Waiting for carrier\n"); 32349472Sbrian return 0; /* A device timer is running to wake us up again */ 32449472Sbrian 32549472Sbrian case CARRIER_OK: 32651978Sbrian if (dl->script.run) { 32751978Sbrian datalink_NewState(dl, DATALINK_LOGIN); 32854914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL)) 32954914Sbrian log_Printf(LogWARN, "Invalid login script\n"); 33051978Sbrian } else 33151978Sbrian datalink_LoginDone(dl); 33249472Sbrian return datalink_UpdateSet(d, r, w, e, n); 33349472Sbrian 33449472Sbrian case CARRIER_LOST: 33549472Sbrian physical_Offline(dl->physical); /* Is this required ? */ 33651978Sbrian if (dl->script.run) { 33751978Sbrian datalink_NewState(dl, DATALINK_HANGUP); 33854914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 33954914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 34053070Sbrian return datalink_UpdateSet(d, r, w, e, n); 34153070Sbrian } else { 34251978Sbrian datalink_HangupDone(dl); 34353070Sbrian return 0; /* Maybe bundle_CleanDatalinks() has something to do */ 34453070Sbrian } 34549472Sbrian } 34649472Sbrian 34736285Sbrian case DATALINK_HANGUP: 34836285Sbrian case DATALINK_DIAL: 34952488Sbrian case DATALINK_LOGOUT: 35036285Sbrian case DATALINK_LOGIN: 35136285Sbrian result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 35236285Sbrian switch (dl->chat.state) { 35336285Sbrian case CHAT_DONE: 35436285Sbrian /* script succeeded */ 35536285Sbrian switch(dl->state) { 35636285Sbrian case DATALINK_HANGUP: 35736285Sbrian datalink_HangupDone(dl); 35836285Sbrian break; 35936285Sbrian case DATALINK_DIAL: 36049472Sbrian datalink_NewState(dl, DATALINK_CARRIER); 36136285Sbrian return datalink_UpdateSet(d, r, w, e, n); 36252488Sbrian case DATALINK_LOGOUT: 36352488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 36452488Sbrian physical_Offline(dl->physical); 36554914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 36654914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 36752488Sbrian return datalink_UpdateSet(d, r, w, e, n); 36836285Sbrian case DATALINK_LOGIN: 36942390Sbrian dl->phone.alt = NULL; 37036285Sbrian datalink_LoginDone(dl); 37142905Sbrian return datalink_UpdateSet(d, r, w, e, n); 37236285Sbrian } 37336285Sbrian break; 37436285Sbrian case CHAT_FAILED: 37536285Sbrian /* Going down - script failed */ 37636285Sbrian log_Printf(LogWARN, "Chat script failed\n"); 37736285Sbrian switch(dl->state) { 37836285Sbrian case DATALINK_HANGUP: 37936285Sbrian datalink_HangupDone(dl); 38036285Sbrian break; 38136285Sbrian case DATALINK_DIAL: 38252488Sbrian case DATALINK_LOGOUT: 38336285Sbrian case DATALINK_LOGIN: 38436285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 38552488Sbrian physical_Offline(dl->physical); 38654914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 38754914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 38836285Sbrian return datalink_UpdateSet(d, r, w, e, n); 38936285Sbrian } 39036285Sbrian break; 39136285Sbrian } 39236285Sbrian break; 39336285Sbrian 39436285Sbrian case DATALINK_READY: 39536285Sbrian case DATALINK_LCP: 39636285Sbrian case DATALINK_AUTH: 39738174Sbrian case DATALINK_CBCP: 39836285Sbrian case DATALINK_OPEN: 39943888Sbrian result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 40043888Sbrian descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 40136285Sbrian break; 40236285Sbrian } 40336285Sbrian return result; 40436285Sbrian} 40536285Sbrian 40636285Sbrianint 40736285Sbriandatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 40836285Sbrian{ 40936285Sbrian return physical_RemoveFromSet(dl->physical, r, w, e); 41036285Sbrian} 41136285Sbrian 41236285Sbrianstatic int 41336285Sbriandatalink_IsSet(struct descriptor *d, const fd_set *fdset) 41436285Sbrian{ 41536285Sbrian struct datalink *dl = descriptor2datalink(d); 41636285Sbrian 41736285Sbrian switch (dl->state) { 41836285Sbrian case DATALINK_CLOSED: 41936285Sbrian case DATALINK_OPENING: 42036285Sbrian break; 42136285Sbrian 42236285Sbrian case DATALINK_HANGUP: 42336285Sbrian case DATALINK_DIAL: 42452488Sbrian case DATALINK_LOGOUT: 42536285Sbrian case DATALINK_LOGIN: 42636285Sbrian return descriptor_IsSet(&dl->chat.desc, fdset); 42736285Sbrian 42836285Sbrian case DATALINK_READY: 42936285Sbrian case DATALINK_LCP: 43036285Sbrian case DATALINK_AUTH: 43138174Sbrian case DATALINK_CBCP: 43236285Sbrian case DATALINK_OPEN: 43343888Sbrian return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 43443888Sbrian descriptor_IsSet(&dl->physical->desc, fdset); 43536285Sbrian } 43636285Sbrian return 0; 43736285Sbrian} 43836285Sbrian 43936285Sbrianstatic void 44036285Sbriandatalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 44136285Sbrian{ 44236285Sbrian struct datalink *dl = descriptor2datalink(d); 44336285Sbrian 44436285Sbrian switch (dl->state) { 44536285Sbrian case DATALINK_CLOSED: 44636285Sbrian case DATALINK_OPENING: 44736285Sbrian break; 44836285Sbrian 44936285Sbrian case DATALINK_HANGUP: 45036285Sbrian case DATALINK_DIAL: 45152488Sbrian case DATALINK_LOGOUT: 45236285Sbrian case DATALINK_LOGIN: 45336285Sbrian descriptor_Read(&dl->chat.desc, bundle, fdset); 45436285Sbrian break; 45536285Sbrian 45636285Sbrian case DATALINK_READY: 45736285Sbrian case DATALINK_LCP: 45836285Sbrian case DATALINK_AUTH: 45938174Sbrian case DATALINK_CBCP: 46036285Sbrian case DATALINK_OPEN: 46143888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 46243888Sbrian descriptor_Read(&dl->chap.desc, bundle, fdset); 46343888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 46443888Sbrian descriptor_Read(&dl->physical->desc, bundle, fdset); 46536285Sbrian break; 46636285Sbrian } 46736285Sbrian} 46836285Sbrian 46937141Sbrianstatic int 47036285Sbriandatalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 47136285Sbrian{ 47236285Sbrian struct datalink *dl = descriptor2datalink(d); 47337141Sbrian int result = 0; 47436285Sbrian 47536285Sbrian switch (dl->state) { 47636285Sbrian case DATALINK_CLOSED: 47736285Sbrian case DATALINK_OPENING: 47836285Sbrian break; 47936285Sbrian 48036285Sbrian case DATALINK_HANGUP: 48136285Sbrian case DATALINK_DIAL: 48252488Sbrian case DATALINK_LOGOUT: 48336285Sbrian case DATALINK_LOGIN: 48437141Sbrian result = descriptor_Write(&dl->chat.desc, bundle, fdset); 48536285Sbrian break; 48636285Sbrian 48736285Sbrian case DATALINK_READY: 48836285Sbrian case DATALINK_LCP: 48936285Sbrian case DATALINK_AUTH: 49038174Sbrian case DATALINK_CBCP: 49136285Sbrian case DATALINK_OPEN: 49243888Sbrian if (descriptor_IsSet(&dl->chap.desc, fdset)) 49343888Sbrian result += descriptor_Write(&dl->chap.desc, bundle, fdset); 49443888Sbrian if (descriptor_IsSet(&dl->physical->desc, fdset)) 49543888Sbrian result += descriptor_Write(&dl->physical->desc, bundle, fdset); 49636285Sbrian break; 49736285Sbrian } 49837141Sbrian 49937141Sbrian return result; 50036285Sbrian} 50136285Sbrian 50236285Sbrianstatic void 50337007Sbriandatalink_ComeDown(struct datalink *dl, int how) 50436285Sbrian{ 50537007Sbrian if (how != CLOSE_NORMAL) { 50644468Sbrian dl->dial.tries = -1; 50736285Sbrian dl->reconnect_tries = 0; 50837012Sbrian if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 50937007Sbrian dl->stayonline = 1; 51036285Sbrian } 51136285Sbrian 51237012Sbrian if (dl->state >= DATALINK_READY && dl->stayonline) { 51337007Sbrian dl->stayonline = 0; 51447061Sbrian physical_StopDeviceTimer(dl->physical); 51537007Sbrian datalink_NewState(dl, DATALINK_READY); 51637007Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 51746686Sbrian physical_Offline(dl->physical); 51836285Sbrian if (dl->script.run && dl->state != DATALINK_OPENING) { 51952488Sbrian if (dl->state == DATALINK_LOGOUT) { 52052488Sbrian datalink_NewState(dl, DATALINK_HANGUP); 52154914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) 52254914Sbrian log_Printf(LogWARN, "Invalid hangup script\n"); 52352488Sbrian } else { 52452488Sbrian datalink_NewState(dl, DATALINK_LOGOUT); 52554914Sbrian if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) 52654914Sbrian log_Printf(LogWARN, "Invalid logout script\n"); 52752488Sbrian } 52836285Sbrian } else 52936285Sbrian datalink_HangupDone(dl); 53036285Sbrian } 53136285Sbrian} 53236285Sbrian 53336285Sbrianstatic void 53436285Sbriandatalink_LayerStart(void *v, struct fsm *fp) 53536285Sbrian{ 53636285Sbrian /* The given FSM is about to start up ! */ 53736285Sbrian struct datalink *dl = (struct datalink *)v; 53836285Sbrian 53936285Sbrian if (fp->proto == PROTO_LCP) 54036285Sbrian (*dl->parent->LayerStart)(dl->parent->object, fp); 54136285Sbrian} 54236285Sbrian 54336285Sbrianstatic void 54436285Sbriandatalink_LayerUp(void *v, struct fsm *fp) 54536285Sbrian{ 54636285Sbrian /* The given fsm is now up */ 54736285Sbrian struct datalink *dl = (struct datalink *)v; 54844106Sbrian struct lcp *lcp = &dl->physical->link.lcp; 54936285Sbrian 55036285Sbrian if (fp->proto == PROTO_LCP) { 55143693Sbrian datalink_GotAuthname(dl, ""); 55244106Sbrian lcp->auth_ineed = lcp->want_auth; 55344106Sbrian lcp->auth_iwait = lcp->his_auth; 55444106Sbrian if (lcp->his_auth || lcp->want_auth) { 55545350Sbrian if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 55636285Sbrian bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 55736285Sbrian log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 55844106Sbrian Auth2Nam(lcp->his_auth, lcp->his_authtype), 55944106Sbrian Auth2Nam(lcp->want_auth, lcp->want_authtype)); 56044106Sbrian if (lcp->his_auth == PROTO_PAP) 56143693Sbrian auth_StartReq(&dl->pap); 56244106Sbrian if (lcp->want_auth == PROTO_CHAP) 56343693Sbrian auth_StartReq(&dl->chap.auth); 56436285Sbrian } else 56536285Sbrian datalink_AuthOk(dl); 56636285Sbrian } 56736285Sbrian} 56836285Sbrian 56944094Sbrianstatic void 57044094Sbriandatalink_AuthReInit(struct datalink *dl) 57144094Sbrian{ 57244094Sbrian auth_StopTimer(&dl->pap); 57344094Sbrian auth_StopTimer(&dl->chap.auth); 57444094Sbrian chap_ReInit(&dl->chap); 57544094Sbrian} 57644094Sbrian 57736285Sbrianvoid 57843693Sbriandatalink_GotAuthname(struct datalink *dl, const char *name) 57936285Sbrian{ 58043693Sbrian strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 58143693Sbrian dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 58236285Sbrian} 58336285Sbrian 58436285Sbrianvoid 58538174Sbriandatalink_NCPUp(struct datalink *dl) 58636285Sbrian{ 58737320Sbrian int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 58836310Sbrian 58936285Sbrian if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 59036285Sbrian /* we've authenticated in multilink mode ! */ 59136285Sbrian switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 59236285Sbrian case MP_LINKSENT: 59336285Sbrian /* We've handed the link off to another ppp (well, we will soon) ! */ 59436285Sbrian return; 59536285Sbrian case MP_UP: 59636285Sbrian /* First link in the bundle */ 59738174Sbrian auth_Select(dl->bundle, dl->peer.authname); 59849434Sbrian bundle_CalculateBandwidth(dl->bundle); 59936285Sbrian /* fall through */ 60036285Sbrian case MP_ADDED: 60136285Sbrian /* We're in multilink mode ! */ 60236310Sbrian dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 60349434Sbrian bundle_CalculateBandwidth(dl->bundle); 60436285Sbrian break; 60536285Sbrian case MP_FAILED: 60636285Sbrian datalink_AuthNotOk(dl); 60736285Sbrian return; 60836285Sbrian } 60936285Sbrian } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 61036285Sbrian log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 61137160Sbrian datalink_NewState(dl, DATALINK_OPEN); 61249434Sbrian bundle_CalculateBandwidth(dl->bundle); 61337160Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 61436285Sbrian return; 61536285Sbrian } else { 61636285Sbrian dl->bundle->ncp.mp.peer = dl->peer; 61736285Sbrian ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 61838174Sbrian auth_Select(dl->bundle, dl->peer.authname); 61936285Sbrian } 62036285Sbrian 62137320Sbrian if (ccpok) { 62237320Sbrian fsm_Up(&dl->physical->link.ccp.fsm); 62337320Sbrian fsm_Open(&dl->physical->link.ccp.fsm); 62437320Sbrian } 62536285Sbrian datalink_NewState(dl, DATALINK_OPEN); 62636285Sbrian bundle_NewPhase(dl->bundle, PHASE_NETWORK); 62736285Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 62836285Sbrian} 62936285Sbrian 63036285Sbrianvoid 63138174Sbriandatalink_CBCPComplete(struct datalink *dl) 63238174Sbrian{ 63338174Sbrian datalink_NewState(dl, DATALINK_LCP); 63444094Sbrian datalink_AuthReInit(dl); 63538174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 63638174Sbrian} 63738174Sbrian 63838174Sbrianvoid 63938174Sbriandatalink_CBCPFailed(struct datalink *dl) 64038174Sbrian{ 64138174Sbrian cbcp_Down(&dl->cbcp); 64238174Sbrian datalink_CBCPComplete(dl); 64338174Sbrian} 64438174Sbrian 64538174Sbrianvoid 64638174Sbriandatalink_AuthOk(struct datalink *dl) 64738174Sbrian{ 64842600Sbrian if ((dl->physical->link.lcp.his_callback.opmask & 64942600Sbrian CALLBACK_BIT(CALLBACK_CBCP) || 65042600Sbrian dl->physical->link.lcp.want_callback.opmask & 65142600Sbrian CALLBACK_BIT(CALLBACK_CBCP)) && 65242600Sbrian !(dl->physical->link.lcp.want_callback.opmask & 65342600Sbrian CALLBACK_BIT(CALLBACK_AUTH))) { 65442600Sbrian /* We must have agreed CBCP if AUTH isn't there any more */ 65538174Sbrian datalink_NewState(dl, DATALINK_CBCP); 65638174Sbrian cbcp_Up(&dl->cbcp); 65738174Sbrian } else if (dl->physical->link.lcp.want_callback.opmask) { 65842600Sbrian /* It's not CBCP */ 65938174Sbrian log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 66038174Sbrian datalink_NewState(dl, DATALINK_LCP); 66144094Sbrian datalink_AuthReInit(dl); 66238174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 66338174Sbrian } else 66438174Sbrian switch (dl->physical->link.lcp.his_callback.opmask) { 66538174Sbrian case 0: 66638174Sbrian datalink_NCPUp(dl); 66738174Sbrian break; 66838174Sbrian 66938174Sbrian case CALLBACK_BIT(CALLBACK_AUTH): 67038174Sbrian auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 67138174Sbrian sizeof dl->cbcp.fsm.phone); 67238174Sbrian if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 67338174Sbrian log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 67438174Sbrian dl->peer.authname); 67538174Sbrian *dl->cbcp.fsm.phone = '\0'; 67638174Sbrian } else { 67738174Sbrian char *ptr = strchr(dl->cbcp.fsm.phone, ','); 67838174Sbrian if (ptr) 67938174Sbrian *ptr = '\0'; /* Call back on the first number */ 68038174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 68138174Sbrian dl->cbcp.fsm.phone); 68238174Sbrian dl->cbcp.required = 1; 68338174Sbrian } 68438174Sbrian dl->cbcp.fsm.delay = 0; 68538174Sbrian datalink_NewState(dl, DATALINK_LCP); 68644094Sbrian datalink_AuthReInit(dl); 68738174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 68838174Sbrian break; 68938174Sbrian 69038174Sbrian case CALLBACK_BIT(CALLBACK_E164): 69138174Sbrian strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 69238174Sbrian sizeof dl->cbcp.fsm.phone - 1); 69338174Sbrian dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 69438174Sbrian log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 69538174Sbrian dl->cbcp.fsm.phone); 69638174Sbrian dl->cbcp.required = 1; 69738174Sbrian dl->cbcp.fsm.delay = 0; 69838174Sbrian datalink_NewState(dl, DATALINK_LCP); 69944094Sbrian datalink_AuthReInit(dl); 70038174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 70138174Sbrian break; 70238174Sbrian 70338174Sbrian default: 70438174Sbrian log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 70538174Sbrian dl->name); 70638174Sbrian datalink_NewState(dl, DATALINK_LCP); 70744094Sbrian datalink_AuthReInit(dl); 70838174Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 70938174Sbrian break; 71038174Sbrian } 71138174Sbrian} 71238174Sbrian 71338174Sbrianvoid 71436285Sbriandatalink_AuthNotOk(struct datalink *dl) 71536285Sbrian{ 71636285Sbrian datalink_NewState(dl, DATALINK_LCP); 71744094Sbrian datalink_AuthReInit(dl); 71836285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 71936285Sbrian} 72036285Sbrian 72136285Sbrianstatic void 72236285Sbriandatalink_LayerDown(void *v, struct fsm *fp) 72336285Sbrian{ 72436285Sbrian /* The given FSM has been told to come down */ 72536285Sbrian struct datalink *dl = (struct datalink *)v; 72636285Sbrian 72736285Sbrian if (fp->proto == PROTO_LCP) { 72836285Sbrian switch (dl->state) { 72936285Sbrian case DATALINK_OPEN: 73036285Sbrian peerid_Init(&dl->peer); 73137060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 73236928Sbrian datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 73336285Sbrian (*dl->parent->LayerDown)(dl->parent->object, fp); 73438174Sbrian /* fall through (just in case) */ 73536285Sbrian 73638174Sbrian case DATALINK_CBCP: 73738174Sbrian if (!dl->cbcp.required) 73838174Sbrian cbcp_Down(&dl->cbcp); 73938174Sbrian /* fall through (just in case) */ 74038174Sbrian 74136285Sbrian case DATALINK_AUTH: 74236285Sbrian timer_Stop(&dl->pap.authtimer); 74336285Sbrian timer_Stop(&dl->chap.auth.authtimer); 74436285Sbrian } 74536285Sbrian datalink_NewState(dl, DATALINK_LCP); 74644094Sbrian datalink_AuthReInit(dl); 74736285Sbrian } 74836285Sbrian} 74936285Sbrian 75036285Sbrianstatic void 75136285Sbriandatalink_LayerFinish(void *v, struct fsm *fp) 75236285Sbrian{ 75336285Sbrian /* The given fsm is now down */ 75436285Sbrian struct datalink *dl = (struct datalink *)v; 75536285Sbrian 75636285Sbrian if (fp->proto == PROTO_LCP) { 75737060Sbrian fsm2initial(fp); 75836285Sbrian (*dl->parent->LayerFinish)(dl->parent->object, fp); 75937007Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 76036285Sbrian } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 76136285Sbrian fsm_Open(fp); /* CCP goes to ST_STOPPED */ 76236285Sbrian} 76336285Sbrian 76436285Sbrianstruct datalink * 76536285Sbriandatalink_Create(const char *name, struct bundle *bundle, int type) 76636285Sbrian{ 76736285Sbrian struct datalink *dl; 76836285Sbrian 76936285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 77036285Sbrian if (dl == NULL) 77136285Sbrian return dl; 77236285Sbrian 77336285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 77436285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 77536285Sbrian dl->desc.IsSet = datalink_IsSet; 77636285Sbrian dl->desc.Read = datalink_Read; 77736285Sbrian dl->desc.Write = datalink_Write; 77836285Sbrian 77936285Sbrian dl->state = DATALINK_CLOSED; 78036285Sbrian 78136285Sbrian *dl->cfg.script.dial = '\0'; 78236285Sbrian *dl->cfg.script.login = '\0'; 78352488Sbrian *dl->cfg.script.logout = '\0'; 78436285Sbrian *dl->cfg.script.hangup = '\0'; 78536285Sbrian *dl->cfg.phone.list = '\0'; 78636285Sbrian *dl->phone.list = '\0'; 78736285Sbrian dl->phone.next = NULL; 78836285Sbrian dl->phone.alt = NULL; 78936285Sbrian dl->phone.chosen = "N/A"; 79037007Sbrian dl->stayonline = 0; 79136285Sbrian dl->script.run = 1; 79236285Sbrian dl->script.packetmode = 1; 79336285Sbrian mp_linkInit(&dl->mp); 79436285Sbrian 79536285Sbrian dl->bundle = bundle; 79636285Sbrian dl->next = NULL; 79736285Sbrian 79844468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 79936285Sbrian 80044468Sbrian dl->dial.tries = 0; 80136285Sbrian dl->cfg.dial.max = 1; 80236285Sbrian dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 80336285Sbrian dl->cfg.dial.timeout = DIAL_TIMEOUT; 80444468Sbrian dl->cfg.dial.inc = 0; 80544468Sbrian dl->cfg.dial.maxinc = 10; 80636285Sbrian 80736285Sbrian dl->reconnect_tries = 0; 80836285Sbrian dl->cfg.reconnect.max = 0; 80936285Sbrian dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 81036285Sbrian 81138174Sbrian dl->cfg.callback.opmask = 0; 81238174Sbrian dl->cfg.cbcp.delay = 0; 81338174Sbrian *dl->cfg.cbcp.phone = '\0'; 81438174Sbrian dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 81538174Sbrian 81636285Sbrian dl->name = strdup(name); 81736285Sbrian peerid_Init(&dl->peer); 81836285Sbrian dl->parent = &bundle->fsm; 81936285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 82036285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 82136285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 82236285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 82336285Sbrian dl->fsmp.object = dl; 82436285Sbrian 82546686Sbrian if ((dl->physical = physical_Create(dl, type)) == NULL) { 82636285Sbrian free(dl->name); 82736285Sbrian free(dl); 82836285Sbrian return NULL; 82936285Sbrian } 83043693Sbrian 83143693Sbrian pap_Init(&dl->pap, dl->physical); 83243693Sbrian chap_Init(&dl->chap, dl->physical); 83338174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 83436285Sbrian 83552488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 83654055Sbrian chat_Init(&dl->chat, dl->physical); 83752488Sbrian 83836285Sbrian log_Printf(LogPHASE, "%s: Created in %s state\n", 83936285Sbrian dl->name, datalink_State(dl)); 84036285Sbrian 84136285Sbrian return dl; 84236285Sbrian} 84336285Sbrian 84436285Sbrianstruct datalink * 84536285Sbriandatalink_Clone(struct datalink *odl, const char *name) 84636285Sbrian{ 84736285Sbrian struct datalink *dl; 84836285Sbrian 84936285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 85036285Sbrian if (dl == NULL) 85136285Sbrian return dl; 85236285Sbrian 85336285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 85436285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 85536285Sbrian dl->desc.IsSet = datalink_IsSet; 85636285Sbrian dl->desc.Read = datalink_Read; 85736285Sbrian dl->desc.Write = datalink_Write; 85836285Sbrian 85936285Sbrian dl->state = DATALINK_CLOSED; 86036285Sbrian 86136285Sbrian memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 86236285Sbrian mp_linkInit(&dl->mp); 86336285Sbrian *dl->phone.list = '\0'; 86436285Sbrian dl->phone.next = NULL; 86536285Sbrian dl->phone.alt = NULL; 86636285Sbrian dl->phone.chosen = "N/A"; 86736285Sbrian dl->bundle = odl->bundle; 86836285Sbrian dl->next = NULL; 86944468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 87044468Sbrian dl->dial.tries = 0; 87136285Sbrian dl->reconnect_tries = 0; 87236285Sbrian dl->name = strdup(name); 87336285Sbrian peerid_Init(&dl->peer); 87436285Sbrian dl->parent = odl->parent; 87536285Sbrian memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 87636285Sbrian dl->fsmp.object = dl; 87736285Sbrian 87846686Sbrian if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { 87936285Sbrian free(dl->name); 88036285Sbrian free(dl); 88136285Sbrian return NULL; 88236285Sbrian } 88343693Sbrian pap_Init(&dl->pap, dl->physical); 88444305Sbrian dl->pap.cfg = odl->pap.cfg; 88543693Sbrian 88643693Sbrian chap_Init(&dl->chap, dl->physical); 88744305Sbrian dl->chap.auth.cfg = odl->chap.auth.cfg; 88843693Sbrian 88936285Sbrian memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 89036285Sbrian memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 89136285Sbrian sizeof dl->physical->link.lcp.cfg); 89236285Sbrian memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 89336285Sbrian sizeof dl->physical->link.ccp.cfg); 89436285Sbrian memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 89536285Sbrian sizeof dl->physical->async.cfg); 89636285Sbrian 89738174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 89836285Sbrian 89952488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 90054055Sbrian chat_Init(&dl->chat, dl->physical); 90152488Sbrian 90236285Sbrian log_Printf(LogPHASE, "%s: Cloned in %s state\n", 90336285Sbrian dl->name, datalink_State(dl)); 90436285Sbrian 90536285Sbrian return dl; 90636285Sbrian} 90736285Sbrian 90836285Sbrianstruct datalink * 90936285Sbriandatalink_Destroy(struct datalink *dl) 91036285Sbrian{ 91136285Sbrian struct datalink *result; 91236285Sbrian 91336285Sbrian if (dl->state != DATALINK_CLOSED) { 91436285Sbrian log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 91536285Sbrian datalink_State(dl)); 91636285Sbrian switch (dl->state) { 91736285Sbrian case DATALINK_HANGUP: 91836285Sbrian case DATALINK_DIAL: 91936285Sbrian case DATALINK_LOGIN: 92054055Sbrian chat_Finish(&dl->chat); /* Gotta blat the timers ! */ 92136285Sbrian break; 92236285Sbrian } 92336285Sbrian } 92436285Sbrian 92554055Sbrian chat_Destroy(&dl->chat); 92644468Sbrian timer_Stop(&dl->dial.timer); 92736285Sbrian result = dl->next; 92846686Sbrian physical_Destroy(dl->physical); 92936285Sbrian free(dl->name); 93036285Sbrian free(dl); 93136285Sbrian 93236285Sbrian return result; 93336285Sbrian} 93436285Sbrian 93536285Sbrianvoid 93636285Sbriandatalink_Up(struct datalink *dl, int runscripts, int packetmode) 93736285Sbrian{ 93836285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 93936285Sbrian /* Ignore scripts */ 94036285Sbrian runscripts = 0; 94136285Sbrian 94236285Sbrian switch (dl->state) { 94336285Sbrian case DATALINK_CLOSED: 94436285Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 94536285Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 94636285Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 94736285Sbrian datalink_NewState(dl, DATALINK_OPENING); 94836285Sbrian dl->reconnect_tries = 94936285Sbrian dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 95044468Sbrian dl->dial.tries = dl->cfg.dial.max; 95136285Sbrian dl->script.run = runscripts; 95236285Sbrian dl->script.packetmode = packetmode; 95336285Sbrian break; 95436285Sbrian 95536285Sbrian case DATALINK_OPENING: 95636285Sbrian if (!dl->script.run && runscripts) 95736285Sbrian dl->script.run = 1; 95836285Sbrian /* fall through */ 95936285Sbrian 96036285Sbrian case DATALINK_DIAL: 96136285Sbrian case DATALINK_LOGIN: 96236285Sbrian case DATALINK_READY: 96336285Sbrian if (!dl->script.packetmode && packetmode) { 96436285Sbrian dl->script.packetmode = 1; 96536285Sbrian if (dl->state == DATALINK_READY) 96636285Sbrian datalink_LoginDone(dl); 96736285Sbrian } 96836285Sbrian break; 96936285Sbrian } 97036285Sbrian} 97136285Sbrian 97236285Sbrianvoid 97337007Sbriandatalink_Close(struct datalink *dl, int how) 97436285Sbrian{ 97536285Sbrian /* Please close */ 97636285Sbrian switch (dl->state) { 97736285Sbrian case DATALINK_OPEN: 97836285Sbrian peerid_Init(&dl->peer); 97937060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 98036285Sbrian /* fall through */ 98136285Sbrian 98238174Sbrian case DATALINK_CBCP: 98336285Sbrian case DATALINK_AUTH: 98436285Sbrian case DATALINK_LCP: 98544094Sbrian datalink_AuthReInit(dl); 98636285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 98737007Sbrian if (how != CLOSE_NORMAL) { 98844468Sbrian dl->dial.tries = -1; 98936285Sbrian dl->reconnect_tries = 0; 99037007Sbrian if (how == CLOSE_LCP) 99137007Sbrian dl->stayonline = 1; 99236285Sbrian } 99352029Sbrian break; 99436285Sbrian 99536285Sbrian default: 99637007Sbrian datalink_ComeDown(dl, how); 99736285Sbrian } 99836285Sbrian} 99936285Sbrian 100036285Sbrianvoid 100137007Sbriandatalink_Down(struct datalink *dl, int how) 100236285Sbrian{ 100336285Sbrian /* Carrier is lost */ 100436285Sbrian switch (dl->state) { 100536285Sbrian case DATALINK_OPEN: 100636285Sbrian peerid_Init(&dl->peer); 100737060Sbrian fsm2initial(&dl->physical->link.ccp.fsm); 100836285Sbrian /* fall through */ 100936285Sbrian 101038174Sbrian case DATALINK_CBCP: 101136285Sbrian case DATALINK_AUTH: 101236285Sbrian case DATALINK_LCP: 101337060Sbrian fsm2initial(&dl->physical->link.lcp.fsm); 101436285Sbrian /* fall through */ 101536285Sbrian 101636285Sbrian default: 101737007Sbrian datalink_ComeDown(dl, how); 101836285Sbrian } 101936285Sbrian} 102036285Sbrian 102136285Sbrianvoid 102236285Sbriandatalink_StayDown(struct datalink *dl) 102336285Sbrian{ 102436285Sbrian dl->reconnect_tries = 0; 102536285Sbrian} 102636285Sbrian 102737007Sbrianvoid 102837007Sbriandatalink_DontHangup(struct datalink *dl) 102937007Sbrian{ 103037012Sbrian if (dl->state >= DATALINK_LCP) 103137012Sbrian dl->stayonline = 1; 103237007Sbrian} 103337007Sbrian 103436285Sbrianint 103536285Sbriandatalink_Show(struct cmdargs const *arg) 103636285Sbrian{ 103736285Sbrian prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 103838174Sbrian prompt_Printf(arg->prompt, " State: %s\n", 103936285Sbrian datalink_State(arg->cx)); 104038174Sbrian prompt_Printf(arg->prompt, " Peer name: "); 104136285Sbrian if (*arg->cx->peer.authname) 104236285Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 104336285Sbrian else if (arg->cx->state == DATALINK_OPEN) 104436285Sbrian prompt_Printf(arg->prompt, "None requested\n"); 104536285Sbrian else 104636285Sbrian prompt_Printf(arg->prompt, "N/A\n"); 104738174Sbrian prompt_Printf(arg->prompt, " Discriminator: %s\n", 104836285Sbrian mp_Enddisc(arg->cx->peer.enddisc.class, 104936285Sbrian arg->cx->peer.enddisc.address, 105036285Sbrian arg->cx->peer.enddisc.len)); 105136285Sbrian 105236285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 105338174Sbrian prompt_Printf(arg->prompt, " Phone List: %s\n", 105436285Sbrian arg->cx->cfg.phone.list); 105536285Sbrian if (arg->cx->cfg.dial.max) 105638174Sbrian prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 105736285Sbrian arg->cx->cfg.dial.max); 105836285Sbrian else 105938174Sbrian prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 106044261Sbrian if (arg->cx->cfg.dial.next_timeout >= 0) 106136285Sbrian prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 106236285Sbrian else 106336285Sbrian prompt_Printf(arg->prompt, "random/"); 106444261Sbrian if (arg->cx->cfg.dial.timeout >= 0) 106536285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 106636285Sbrian else 106736285Sbrian prompt_Printf(arg->prompt, "random\n"); 106838174Sbrian prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 106936285Sbrian arg->cx->cfg.reconnect.max); 107036285Sbrian if (arg->cx->cfg.reconnect.timeout > 0) 107136285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 107236285Sbrian else 107336285Sbrian prompt_Printf(arg->prompt, "random\n"); 107438174Sbrian prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 107538174Sbrian PHYS_DIRECT ? "accepted: " : "requested:"); 107638174Sbrian if (!arg->cx->cfg.callback.opmask) 107738174Sbrian prompt_Printf(arg->prompt, "none\n"); 107838174Sbrian else { 107938174Sbrian int comma = 0; 108038174Sbrian 108138174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 108238174Sbrian prompt_Printf(arg->prompt, "none"); 108338174Sbrian comma = 1; 108438174Sbrian } 108538174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 108638174Sbrian prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 108738174Sbrian comma = 1; 108838174Sbrian } 108938174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 109038174Sbrian prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 109138174Sbrian if (arg->cx->physical->type != PHYS_DIRECT) 109238174Sbrian prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 109338174Sbrian comma = 1; 109438174Sbrian } 109538174Sbrian if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 109638174Sbrian prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 109738174Sbrian prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 109838174Sbrian arg->cx->cfg.cbcp.delay); 109940483Sbrian prompt_Printf(arg->prompt, " phone: "); 110040483Sbrian if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 110140483Sbrian if (arg->cx->physical->type & PHYS_DIRECT) 110240483Sbrian prompt_Printf(arg->prompt, "Caller decides\n"); 110340483Sbrian else 110440483Sbrian prompt_Printf(arg->prompt, "Dialback server decides\n"); 110540483Sbrian } else 110640483Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 110738174Sbrian prompt_Printf(arg->prompt, " timeout: %lds\n", 110838174Sbrian arg->cx->cfg.cbcp.fsmretry); 110938174Sbrian } else 111038174Sbrian prompt_Printf(arg->prompt, "\n"); 111138174Sbrian } 111238174Sbrian 111338174Sbrian prompt_Printf(arg->prompt, " Dial Script: %s\n", 111436285Sbrian arg->cx->cfg.script.dial); 111538174Sbrian prompt_Printf(arg->prompt, " Login Script: %s\n", 111636285Sbrian arg->cx->cfg.script.login); 111752488Sbrian prompt_Printf(arg->prompt, " Logout Script: %s\n", 111852488Sbrian arg->cx->cfg.script.logout); 111938174Sbrian prompt_Printf(arg->prompt, " Hangup Script: %s\n", 112036285Sbrian arg->cx->cfg.script.hangup); 112136285Sbrian return 0; 112236285Sbrian} 112336285Sbrian 112436285Sbrianint 112536285Sbriandatalink_SetReconnect(struct cmdargs const *arg) 112636285Sbrian{ 112736285Sbrian if (arg->argc == arg->argn+2) { 112836285Sbrian arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 112936285Sbrian arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 113036285Sbrian return 0; 113136285Sbrian } 113236285Sbrian return -1; 113336285Sbrian} 113436285Sbrian 113536285Sbrianint 113636285Sbriandatalink_SetRedial(struct cmdargs const *arg) 113736285Sbrian{ 113844468Sbrian const char *sep, *osep; 113944468Sbrian int timeout, inc, maxinc, tries; 114036285Sbrian 114136285Sbrian if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 114236285Sbrian if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 114336285Sbrian (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 114436285Sbrian arg->cx->cfg.dial.timeout = -1; 114536285Sbrian randinit(); 114636285Sbrian } else { 114736285Sbrian timeout = atoi(arg->argv[arg->argn]); 114836285Sbrian 114936285Sbrian if (timeout >= 0) 115036285Sbrian arg->cx->cfg.dial.timeout = timeout; 115136285Sbrian else { 115236285Sbrian log_Printf(LogWARN, "Invalid redial timeout\n"); 115336285Sbrian return -1; 115436285Sbrian } 115536285Sbrian } 115636285Sbrian 115744468Sbrian sep = strchr(arg->argv[arg->argn], '+'); 115844468Sbrian if (sep) { 115944468Sbrian inc = atoi(++sep); 116044468Sbrian osep = sep; 116144468Sbrian if (inc >= 0) 116244468Sbrian arg->cx->cfg.dial.inc = inc; 116344468Sbrian else { 116444468Sbrian log_Printf(LogWARN, "Invalid timeout increment\n"); 116544468Sbrian return -1; 116644468Sbrian } 116744468Sbrian sep = strchr(sep, '-'); 116844468Sbrian if (sep) { 116944468Sbrian maxinc = atoi(++sep); 117044468Sbrian if (maxinc >= 0) 117144468Sbrian arg->cx->cfg.dial.maxinc = maxinc; 117244468Sbrian else { 117344468Sbrian log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 117444468Sbrian return -1; 117544468Sbrian } 117644468Sbrian } else { 117744468Sbrian /* Default timeout increment */ 117844468Sbrian arg->cx->cfg.dial.maxinc = 10; 117944468Sbrian sep = osep; 118044468Sbrian } 118144468Sbrian } else { 118244468Sbrian /* Default timeout increment & max increment */ 118344468Sbrian arg->cx->cfg.dial.inc = 0; 118444468Sbrian arg->cx->cfg.dial.maxinc = 10; 118544468Sbrian sep = arg->argv[arg->argn]; 118644468Sbrian } 118744468Sbrian 118844468Sbrian sep = strchr(sep, '.'); 118944468Sbrian if (sep) { 119044468Sbrian if (strcasecmp(++sep, "random") == 0) { 119136285Sbrian arg->cx->cfg.dial.next_timeout = -1; 119236285Sbrian randinit(); 119336285Sbrian } else { 119444468Sbrian timeout = atoi(sep); 119536285Sbrian if (timeout >= 0) 119636285Sbrian arg->cx->cfg.dial.next_timeout = timeout; 119736285Sbrian else { 119836285Sbrian log_Printf(LogWARN, "Invalid next redial timeout\n"); 119936285Sbrian return -1; 120036285Sbrian } 120136285Sbrian } 120236285Sbrian } else 120336285Sbrian /* Default next timeout */ 120436285Sbrian arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 120536285Sbrian 120636285Sbrian if (arg->argc == arg->argn+2) { 120736285Sbrian tries = atoi(arg->argv[arg->argn+1]); 120836285Sbrian 120936285Sbrian if (tries >= 0) { 121036285Sbrian arg->cx->cfg.dial.max = tries; 121136285Sbrian } else { 121236285Sbrian log_Printf(LogWARN, "Invalid retry value\n"); 121336285Sbrian return 1; 121436285Sbrian } 121536285Sbrian } 121636285Sbrian return 0; 121736285Sbrian } 121844468Sbrian 121936285Sbrian return -1; 122036285Sbrian} 122136285Sbrian 122236285Sbrianstatic const char *states[] = { 122336285Sbrian "closed", 122436285Sbrian "opening", 122536285Sbrian "hangup", 122636285Sbrian "dial", 122749472Sbrian "carrier", 122852488Sbrian "logout", 122936285Sbrian "login", 123036285Sbrian "ready", 123136285Sbrian "lcp", 123236285Sbrian "auth", 123338174Sbrian "cbcp", 123436285Sbrian "open" 123536285Sbrian}; 123636285Sbrian 123736285Sbrianconst char * 123836285Sbriandatalink_State(struct datalink *dl) 123936285Sbrian{ 124036285Sbrian if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 124136285Sbrian return "unknown"; 124236285Sbrian return states[dl->state]; 124336285Sbrian} 124436285Sbrian 124536285Sbrianstatic void 124636285Sbriandatalink_NewState(struct datalink *dl, int state) 124736285Sbrian{ 124836285Sbrian if (state != dl->state) { 124936285Sbrian if (state >= 0 && state < sizeof states / sizeof states[0]) { 125036285Sbrian log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 125136285Sbrian states[state]); 125236285Sbrian dl->state = state; 125336285Sbrian } else 125436285Sbrian log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 125536285Sbrian } 125636285Sbrian} 125736285Sbrian 125836285Sbrianstruct datalink * 125936285Sbrianiov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 126052942Sbrian int fd, int *auxfd, int *nauxfd) 126136285Sbrian{ 126236285Sbrian struct datalink *dl, *cdl; 126344305Sbrian struct fsm_retry copy; 126436285Sbrian char *oname; 126536285Sbrian 126636285Sbrian dl = (struct datalink *)iov[(*niov)++].iov_base; 126736285Sbrian dl->name = iov[*niov].iov_base; 126836285Sbrian 126936285Sbrian if (dl->name[DATALINK_MAXNAME-1]) { 127036285Sbrian dl->name[DATALINK_MAXNAME-1] = '\0'; 127136285Sbrian if (strlen(dl->name) == DATALINK_MAXNAME - 1) 127236285Sbrian log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 127336285Sbrian } 127436285Sbrian 127536285Sbrian /* Make sure the name is unique ! */ 127636285Sbrian oname = NULL; 127736285Sbrian do { 127836285Sbrian for (cdl = bundle->links; cdl; cdl = cdl->next) 127936285Sbrian if (!strcasecmp(dl->name, cdl->name)) { 128036285Sbrian if (oname) 128136285Sbrian free(datalink_NextName(dl)); 128236285Sbrian else 128336285Sbrian oname = datalink_NextName(dl); 128436285Sbrian break; /* Keep renaming 'till we have no conflicts */ 128536285Sbrian } 128636285Sbrian } while (cdl); 128736285Sbrian 128836285Sbrian if (oname) { 128936285Sbrian log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 129036285Sbrian free(oname); 129136285Sbrian } else { 129236285Sbrian dl->name = strdup(dl->name); 129336285Sbrian free(iov[*niov].iov_base); 129436285Sbrian } 129536285Sbrian (*niov)++; 129636285Sbrian 129736285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 129836285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 129936285Sbrian dl->desc.IsSet = datalink_IsSet; 130036285Sbrian dl->desc.Read = datalink_Read; 130136285Sbrian dl->desc.Write = datalink_Write; 130236285Sbrian 130336285Sbrian mp_linkInit(&dl->mp); 130436285Sbrian *dl->phone.list = '\0'; 130536285Sbrian dl->phone.next = NULL; 130636285Sbrian dl->phone.alt = NULL; 130736285Sbrian dl->phone.chosen = "N/A"; 130836285Sbrian 130936285Sbrian dl->bundle = bundle; 131036285Sbrian dl->next = NULL; 131144468Sbrian memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 131244468Sbrian dl->dial.tries = 0; 131336285Sbrian dl->reconnect_tries = 0; 131436285Sbrian dl->parent = &bundle->fsm; 131536285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 131636285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 131736285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 131836285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 131936285Sbrian dl->fsmp.object = dl; 132036285Sbrian 132152942Sbrian dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); 132236285Sbrian 132336285Sbrian if (!dl->physical) { 132436285Sbrian free(dl->name); 132536285Sbrian free(dl); 132636285Sbrian dl = NULL; 132736285Sbrian } else { 132844305Sbrian copy = dl->pap.cfg.fsm; 132943693Sbrian pap_Init(&dl->pap, dl->physical); 133044305Sbrian dl->pap.cfg.fsm = copy; 133143693Sbrian 133244305Sbrian copy = dl->chap.auth.cfg.fsm; 133343693Sbrian chap_Init(&dl->chap, dl->physical); 133444305Sbrian dl->chap.auth.cfg.fsm = copy; 133543693Sbrian 133638174Sbrian cbcp_Init(&dl->cbcp, dl->physical); 133736285Sbrian 133852488Sbrian memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ 133954055Sbrian chat_Init(&dl->chat, dl->physical); 134052488Sbrian 134136285Sbrian log_Printf(LogPHASE, "%s: Transferred in %s state\n", 134236285Sbrian dl->name, datalink_State(dl)); 134336285Sbrian } 134436285Sbrian 134536285Sbrian return dl; 134636285Sbrian} 134736285Sbrian 134836285Sbrianint 134936450Sbriandatalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 135053684Sbrian int *auxfd, int *nauxfd) 135136285Sbrian{ 135236285Sbrian /* If `dl' is NULL, we're allocating before a Fromiov() */ 135336285Sbrian int link_fd; 135436285Sbrian 135536285Sbrian if (dl) { 135644468Sbrian timer_Stop(&dl->dial.timer); 135738174Sbrian /* The following is purely for the sake of paranoia */ 135838174Sbrian cbcp_Down(&dl->cbcp); 135936285Sbrian timer_Stop(&dl->pap.authtimer); 136036285Sbrian timer_Stop(&dl->chap.auth.authtimer); 136136285Sbrian } 136236285Sbrian 136336285Sbrian if (*niov >= maxiov - 1) { 136436285Sbrian log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 136536285Sbrian if (dl) { 136636285Sbrian free(dl->name); 136736285Sbrian free(dl); 136836285Sbrian } 136936285Sbrian return -1; 137036285Sbrian } 137136285Sbrian 137253684Sbrian iov[*niov].iov_base = (void *)dl; 137336285Sbrian iov[(*niov)++].iov_len = sizeof *dl; 137453684Sbrian iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL; 137536285Sbrian iov[(*niov)++].iov_len = DATALINK_MAXNAME; 137636285Sbrian 137752942Sbrian link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, 137853684Sbrian nauxfd); 137936285Sbrian 138036285Sbrian if (link_fd == -1 && dl) { 138136285Sbrian free(dl->name); 138236285Sbrian free(dl); 138336285Sbrian } 138436285Sbrian 138536285Sbrian return link_fd; 138636285Sbrian} 138736285Sbrian 138836285Sbrianvoid 138936285Sbriandatalink_Rename(struct datalink *dl, const char *name) 139036285Sbrian{ 139136285Sbrian free(dl->name); 139236285Sbrian dl->physical->link.name = dl->name = strdup(name); 139336285Sbrian} 139436285Sbrian 139536285Sbrianchar * 139636285Sbriandatalink_NextName(struct datalink *dl) 139736285Sbrian{ 139836285Sbrian int f, n; 139936285Sbrian char *name, *oname; 140036285Sbrian 140136285Sbrian n = strlen(dl->name); 140236285Sbrian name = (char *)malloc(n+3); 140336285Sbrian for (f = n - 1; f >= 0; f--) 140436285Sbrian if (!isdigit(dl->name[f])) 140536285Sbrian break; 140636285Sbrian n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 140736285Sbrian sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 140836285Sbrian oname = dl->name; 140936345Sbrian dl->name = name; 141036345Sbrian /* our physical link name isn't updated (it probably isn't created yet) */ 141136285Sbrian return oname; 141236285Sbrian} 141336285Sbrian 141436285Sbrianint 141536285Sbriandatalink_SetMode(struct datalink *dl, int mode) 141636285Sbrian{ 141736285Sbrian if (!physical_SetMode(dl->physical, mode)) 141836285Sbrian return 0; 141936285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 142036285Sbrian dl->script.run = 0; 142136285Sbrian if (dl->physical->type == PHYS_DIRECT) 142236285Sbrian dl->reconnect_tries = 0; 142353830Sbrian if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) && 142453830Sbrian dl->state <= DATALINK_READY) 142536285Sbrian datalink_Up(dl, 1, 1); 142636285Sbrian return 1; 142736285Sbrian} 142844468Sbrian 142944468Sbrianint 143044468Sbriandatalink_GetDialTimeout(struct datalink *dl) 143144468Sbrian{ 143244468Sbrian int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 143344468Sbrian 143444468Sbrian if (dl->dial.incs < dl->cfg.dial.maxinc) 143544468Sbrian dl->dial.incs++; 143644468Sbrian 143744468Sbrian return result; 143844468Sbrian} 1439