datalink.c revision 37012
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 * 2637012Sbrian * $Id: datalink.c,v 1.9 1998/06/15 19:05:15 brian Exp $ 2736285Sbrian */ 2836285Sbrian 2936285Sbrian#include <sys/types.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#include <unistd.h> 4236285Sbrian 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" 6236285Sbrian#include "bundle.h" 6336285Sbrian#include "chat.h" 6436285Sbrian#include "auth.h" 6536285Sbrian#include "modem.h" 6636285Sbrian#include "prompt.h" 6736285Sbrian#include "lcpproto.h" 6836285Sbrian#include "pap.h" 6936285Sbrian#include "chap.h" 7036285Sbrian#include "command.h" 7136285Sbrian#include "datalink.h" 7236285Sbrian 7336285Sbrianstatic void datalink_LoginDone(struct datalink *); 7436285Sbrianstatic void datalink_NewState(struct datalink *, int); 7536285Sbrian 7636285Sbrianstatic void 7736285Sbriandatalink_OpenTimeout(void *v) 7836285Sbrian{ 7936285Sbrian struct datalink *dl = (struct datalink *)v; 8036285Sbrian 8136285Sbrian timer_Stop(&dl->dial_timer); 8236285Sbrian if (dl->state == DATALINK_OPENING) 8336285Sbrian log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 8436285Sbrian} 8536285Sbrian 8636285Sbrianstatic void 8736285Sbriandatalink_StartDialTimer(struct datalink *dl, int Timeout) 8836285Sbrian{ 8936285Sbrian timer_Stop(&dl->dial_timer); 9036285Sbrian 9136285Sbrian if (Timeout) { 9236285Sbrian if (Timeout > 0) 9336285Sbrian dl->dial_timer.load = Timeout * SECTICKS; 9436285Sbrian else 9536285Sbrian dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; 9636285Sbrian dl->dial_timer.func = datalink_OpenTimeout; 9736285Sbrian dl->dial_timer.name = "dial"; 9836285Sbrian dl->dial_timer.arg = dl; 9936285Sbrian timer_Start(&dl->dial_timer); 10036285Sbrian if (dl->state == DATALINK_OPENING) 10136285Sbrian log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 10236285Sbrian dl->name, Timeout); 10336285Sbrian } 10436285Sbrian} 10536285Sbrian 10636285Sbrianstatic void 10736285Sbriandatalink_HangupDone(struct datalink *dl) 10836285Sbrian{ 10936285Sbrian if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 11036285Sbrian physical_GetFD(dl->physical) != -1) { 11136285Sbrian /* Don't close our modem if the link is dedicated */ 11236285Sbrian datalink_LoginDone(dl); 11336285Sbrian return; 11436285Sbrian } 11536285Sbrian 11636285Sbrian modem_Close(dl->physical); 11736285Sbrian dl->phone.chosen = "N/A"; 11836285Sbrian 11936285Sbrian if (dl->bundle->CleaningUp || 12036285Sbrian (dl->physical->type == PHYS_DIRECT) || 12136285Sbrian ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && 12236465Sbrian !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 12336285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 12436285Sbrian dl->dial_tries = -1; 12536285Sbrian dl->reconnect_tries = 0; 12636285Sbrian bundle_LinkClosed(dl->bundle, dl); 12736285Sbrian if (!dl->bundle->CleaningUp) 12836285Sbrian datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 12936285Sbrian } else { 13036285Sbrian datalink_NewState(dl, DATALINK_OPENING); 13136285Sbrian if (dl->dial_tries < 0) { 13236285Sbrian datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 13336285Sbrian dl->dial_tries = dl->cfg.dial.max; 13436285Sbrian dl->reconnect_tries--; 13536285Sbrian } else { 13636285Sbrian if (dl->phone.next == NULL) 13736285Sbrian datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 13836285Sbrian else 13936285Sbrian datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 14036285Sbrian } 14136285Sbrian } 14236285Sbrian} 14336285Sbrian 14436285Sbrianstatic const char * 14536285Sbriandatalink_ChoosePhoneNumber(struct datalink *dl) 14636285Sbrian{ 14736285Sbrian char *phone; 14836285Sbrian 14936285Sbrian if (dl->phone.alt == NULL) { 15036285Sbrian if (dl->phone.next == NULL) { 15136285Sbrian strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 15236285Sbrian dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 15336285Sbrian dl->phone.next = dl->phone.list; 15436285Sbrian } 15536285Sbrian dl->phone.alt = strsep(&dl->phone.next, ":"); 15636285Sbrian } 15736285Sbrian phone = strsep(&dl->phone.alt, "|"); 15836285Sbrian dl->phone.chosen = *phone ? phone : "[NONE]"; 15936285Sbrian if (*phone) 16036285Sbrian log_Printf(LogPHASE, "Phone: %s\n", phone); 16136285Sbrian return phone; 16236285Sbrian} 16336285Sbrian 16436285Sbrianstatic void 16536285Sbriandatalink_LoginDone(struct datalink *dl) 16636285Sbrian{ 16736285Sbrian if (!dl->script.packetmode) { 16836285Sbrian dl->dial_tries = -1; 16936285Sbrian datalink_NewState(dl, DATALINK_READY); 17036285Sbrian } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 17136285Sbrian dl->dial_tries = 0; 17236285Sbrian log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 17336285Sbrian if (dl->script.run) { 17436285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 17536285Sbrian modem_Offline(dl->physical); 17636285Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 17736285Sbrian } else { 17836285Sbrian if (dl->physical->type == PHYS_DEDICATED) 17936285Sbrian /* force a redial timeout */ 18036285Sbrian modem_Close(dl->physical); 18136285Sbrian datalink_HangupDone(dl); 18236285Sbrian } 18336285Sbrian } else { 18436285Sbrian dl->dial_tries = -1; 18536285Sbrian 18636285Sbrian hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 18736285Sbrian async_Init(&dl->physical->async); 18836285Sbrian 18936285Sbrian lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 19036285Sbrian 0 : dl->physical->link.lcp.cfg.openmode); 19136285Sbrian ccp_Setup(&dl->physical->link.ccp); 19236285Sbrian 19336285Sbrian datalink_NewState(dl, DATALINK_LCP); 19436285Sbrian fsm_Up(&dl->physical->link.lcp.fsm); 19536285Sbrian fsm_Open(&dl->physical->link.lcp.fsm); 19636285Sbrian } 19736285Sbrian} 19836285Sbrian 19936285Sbrianstatic int 20036285Sbriandatalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 20136285Sbrian int *n) 20236285Sbrian{ 20336285Sbrian struct datalink *dl = descriptor2datalink(d); 20436285Sbrian int result; 20536285Sbrian 20636285Sbrian result = 0; 20736285Sbrian switch (dl->state) { 20836285Sbrian case DATALINK_CLOSED: 20936465Sbrian if ((dl->physical->type & 21036465Sbrian (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 21136285Sbrian !bundle_IsDead(dl->bundle)) 21236285Sbrian /* 21336465Sbrian * Our first time in - DEDICATED & DDIAL never come down, and 21436465Sbrian * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 21536465Sbrian * Go to DATALINK_OPENING via datalink_Up() and fall through. 21636285Sbrian */ 21736285Sbrian datalink_Up(dl, 1, 1); 21836285Sbrian else 21936285Sbrian break; 22036285Sbrian /* fall through */ 22136285Sbrian 22236285Sbrian case DATALINK_OPENING: 22336285Sbrian if (dl->dial_timer.state != TIMER_RUNNING) { 22436285Sbrian if (--dl->dial_tries < 0) 22536285Sbrian dl->dial_tries = 0; 22636285Sbrian if (modem_Open(dl->physical, dl->bundle) >= 0) { 22736285Sbrian if (dl->script.run) { 22836285Sbrian datalink_NewState(dl, DATALINK_DIAL); 22936285Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 23036285Sbrian datalink_ChoosePhoneNumber(dl)); 23136465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 23236285Sbrian dl->cfg.dial.max) 23336285Sbrian log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 23436285Sbrian dl->name, dl->cfg.dial.max - dl->dial_tries, 23536285Sbrian dl->cfg.dial.max); 23636285Sbrian return datalink_UpdateSet(d, r, w, e, n); 23736285Sbrian } else 23836285Sbrian datalink_LoginDone(dl); 23936285Sbrian } else { 24036465Sbrian if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 24136285Sbrian dl->cfg.dial.max) 24236285Sbrian log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 24336285Sbrian dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max); 24436285Sbrian else 24536285Sbrian log_Printf(LogCHAT, "Failed to open modem\n"); 24636285Sbrian 24736285Sbrian if (dl->bundle->CleaningUp || 24836465Sbrian (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 24936285Sbrian dl->cfg.dial.max && dl->dial_tries == 0)) { 25036285Sbrian datalink_NewState(dl, DATALINK_CLOSED); 25136285Sbrian dl->reconnect_tries = 0; 25236285Sbrian dl->dial_tries = -1; 25336285Sbrian bundle_LinkClosed(dl->bundle, dl); 25436285Sbrian } 25536285Sbrian if (!dl->bundle->CleaningUp) 25636285Sbrian datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 25736285Sbrian } 25836285Sbrian } 25936285Sbrian break; 26036285Sbrian 26136285Sbrian case DATALINK_HANGUP: 26236285Sbrian case DATALINK_DIAL: 26336285Sbrian case DATALINK_LOGIN: 26436285Sbrian result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 26536285Sbrian switch (dl->chat.state) { 26636285Sbrian case CHAT_DONE: 26736285Sbrian /* script succeeded */ 26836285Sbrian chat_Destroy(&dl->chat); 26936285Sbrian switch(dl->state) { 27036285Sbrian case DATALINK_HANGUP: 27136285Sbrian datalink_HangupDone(dl); 27236285Sbrian break; 27336285Sbrian case DATALINK_DIAL: 27436285Sbrian datalink_NewState(dl, DATALINK_LOGIN); 27536285Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 27636285Sbrian return datalink_UpdateSet(d, r, w, e, n); 27736285Sbrian case DATALINK_LOGIN: 27836285Sbrian datalink_LoginDone(dl); 27936285Sbrian break; 28036285Sbrian } 28136285Sbrian break; 28236285Sbrian case CHAT_FAILED: 28336285Sbrian /* Going down - script failed */ 28436285Sbrian log_Printf(LogWARN, "Chat script failed\n"); 28536285Sbrian chat_Destroy(&dl->chat); 28636285Sbrian switch(dl->state) { 28736285Sbrian case DATALINK_HANGUP: 28836285Sbrian datalink_HangupDone(dl); 28936285Sbrian break; 29036285Sbrian case DATALINK_DIAL: 29136285Sbrian case DATALINK_LOGIN: 29236285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 29336285Sbrian modem_Offline(dl->physical); 29436285Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 29536285Sbrian return datalink_UpdateSet(d, r, w, e, n); 29636285Sbrian } 29736285Sbrian break; 29836285Sbrian } 29936285Sbrian break; 30036285Sbrian 30136285Sbrian case DATALINK_READY: 30236285Sbrian case DATALINK_LCP: 30336285Sbrian case DATALINK_AUTH: 30436285Sbrian case DATALINK_OPEN: 30536285Sbrian result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 30636285Sbrian break; 30736285Sbrian } 30836285Sbrian return result; 30936285Sbrian} 31036285Sbrian 31136285Sbrianint 31236285Sbriandatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 31336285Sbrian{ 31436285Sbrian return physical_RemoveFromSet(dl->physical, r, w, e); 31536285Sbrian} 31636285Sbrian 31736285Sbrianstatic int 31836285Sbriandatalink_IsSet(struct descriptor *d, const fd_set *fdset) 31936285Sbrian{ 32036285Sbrian struct datalink *dl = descriptor2datalink(d); 32136285Sbrian 32236285Sbrian switch (dl->state) { 32336285Sbrian case DATALINK_CLOSED: 32436285Sbrian case DATALINK_OPENING: 32536285Sbrian break; 32636285Sbrian 32736285Sbrian case DATALINK_HANGUP: 32836285Sbrian case DATALINK_DIAL: 32936285Sbrian case DATALINK_LOGIN: 33036285Sbrian return descriptor_IsSet(&dl->chat.desc, fdset); 33136285Sbrian 33236285Sbrian case DATALINK_READY: 33336285Sbrian case DATALINK_LCP: 33436285Sbrian case DATALINK_AUTH: 33536285Sbrian case DATALINK_OPEN: 33636285Sbrian return descriptor_IsSet(&dl->physical->desc, fdset); 33736285Sbrian } 33836285Sbrian return 0; 33936285Sbrian} 34036285Sbrian 34136285Sbrianstatic void 34236285Sbriandatalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 34336285Sbrian{ 34436285Sbrian struct datalink *dl = descriptor2datalink(d); 34536285Sbrian 34636285Sbrian switch (dl->state) { 34736285Sbrian case DATALINK_CLOSED: 34836285Sbrian case DATALINK_OPENING: 34936285Sbrian break; 35036285Sbrian 35136285Sbrian case DATALINK_HANGUP: 35236285Sbrian case DATALINK_DIAL: 35336285Sbrian case DATALINK_LOGIN: 35436285Sbrian descriptor_Read(&dl->chat.desc, bundle, fdset); 35536285Sbrian break; 35636285Sbrian 35736285Sbrian case DATALINK_READY: 35836285Sbrian case DATALINK_LCP: 35936285Sbrian case DATALINK_AUTH: 36036285Sbrian case DATALINK_OPEN: 36136285Sbrian descriptor_Read(&dl->physical->desc, bundle, fdset); 36236285Sbrian break; 36336285Sbrian } 36436285Sbrian} 36536285Sbrian 36636285Sbrianstatic void 36736285Sbriandatalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 36836285Sbrian{ 36936285Sbrian struct datalink *dl = descriptor2datalink(d); 37036285Sbrian 37136285Sbrian switch (dl->state) { 37236285Sbrian case DATALINK_CLOSED: 37336285Sbrian case DATALINK_OPENING: 37436285Sbrian break; 37536285Sbrian 37636285Sbrian case DATALINK_HANGUP: 37736285Sbrian case DATALINK_DIAL: 37836285Sbrian case DATALINK_LOGIN: 37936285Sbrian descriptor_Write(&dl->chat.desc, bundle, fdset); 38036285Sbrian break; 38136285Sbrian 38236285Sbrian case DATALINK_READY: 38336285Sbrian case DATALINK_LCP: 38436285Sbrian case DATALINK_AUTH: 38536285Sbrian case DATALINK_OPEN: 38636285Sbrian descriptor_Write(&dl->physical->desc, bundle, fdset); 38736285Sbrian break; 38836285Sbrian } 38936285Sbrian} 39036285Sbrian 39136285Sbrianstatic void 39237007Sbriandatalink_ComeDown(struct datalink *dl, int how) 39336285Sbrian{ 39437007Sbrian if (how != CLOSE_NORMAL) { 39536285Sbrian dl->dial_tries = -1; 39636285Sbrian dl->reconnect_tries = 0; 39737012Sbrian if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 39837007Sbrian dl->stayonline = 1; 39936285Sbrian } 40036285Sbrian 40137012Sbrian if (dl->state >= DATALINK_READY && dl->stayonline) { 40237007Sbrian dl->stayonline = 0; 40337007Sbrian datalink_NewState(dl, DATALINK_READY); 40437007Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 40536285Sbrian modem_Offline(dl->physical); 40636285Sbrian if (dl->script.run && dl->state != DATALINK_OPENING) { 40736285Sbrian datalink_NewState(dl, DATALINK_HANGUP); 40836285Sbrian chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 40936285Sbrian } else 41036285Sbrian datalink_HangupDone(dl); 41136285Sbrian } 41236285Sbrian} 41336285Sbrian 41436285Sbrianstatic void 41536285Sbriandatalink_LayerStart(void *v, struct fsm *fp) 41636285Sbrian{ 41736285Sbrian /* The given FSM is about to start up ! */ 41836285Sbrian struct datalink *dl = (struct datalink *)v; 41936285Sbrian 42036285Sbrian if (fp->proto == PROTO_LCP) 42136285Sbrian (*dl->parent->LayerStart)(dl->parent->object, fp); 42236285Sbrian} 42336285Sbrian 42436285Sbrianstatic void 42536285Sbriandatalink_LayerUp(void *v, struct fsm *fp) 42636285Sbrian{ 42736285Sbrian /* The given fsm is now up */ 42836285Sbrian struct datalink *dl = (struct datalink *)v; 42936285Sbrian 43036285Sbrian if (fp->proto == PROTO_LCP) { 43136285Sbrian datalink_GotAuthname(dl, "", 0); 43236285Sbrian dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 43336285Sbrian dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 43436285Sbrian if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 43536285Sbrian if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 43636285Sbrian bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 43736285Sbrian log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 43836285Sbrian Auth2Nam(dl->physical->link.lcp.his_auth), 43936285Sbrian Auth2Nam(dl->physical->link.lcp.want_auth)); 44036285Sbrian if (dl->physical->link.lcp.his_auth == PROTO_PAP) 44136285Sbrian auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 44236285Sbrian if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 44336285Sbrian auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 44436285Sbrian } else 44536285Sbrian datalink_AuthOk(dl); 44636285Sbrian } 44736285Sbrian} 44836285Sbrian 44936285Sbrianvoid 45036285Sbriandatalink_GotAuthname(struct datalink *dl, const char *name, int len) 45136285Sbrian{ 45236285Sbrian if (len >= sizeof dl->peer.authname) 45336285Sbrian len = sizeof dl->peer.authname - 1; 45436285Sbrian strncpy(dl->peer.authname, name, len); 45536285Sbrian dl->peer.authname[len] = '\0'; 45636285Sbrian} 45736285Sbrian 45836285Sbrianvoid 45936285Sbriandatalink_AuthOk(struct datalink *dl) 46036285Sbrian{ 46136310Sbrian ccp_SetOpenMode(&dl->physical->link.ccp); 46236310Sbrian 46336285Sbrian if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 46436285Sbrian /* we've authenticated in multilink mode ! */ 46536285Sbrian switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 46636285Sbrian case MP_LINKSENT: 46736285Sbrian /* We've handed the link off to another ppp (well, we will soon) ! */ 46836285Sbrian return; 46936285Sbrian case MP_UP: 47036285Sbrian /* First link in the bundle */ 47136285Sbrian auth_Select(dl->bundle, dl->peer.authname, dl->physical); 47236285Sbrian /* fall through */ 47336285Sbrian case MP_ADDED: 47436285Sbrian /* We're in multilink mode ! */ 47536310Sbrian dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 47636285Sbrian break; 47736285Sbrian case MP_FAILED: 47836285Sbrian datalink_AuthNotOk(dl); 47936285Sbrian return; 48036285Sbrian } 48136285Sbrian } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 48236285Sbrian log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 48336285Sbrian datalink_AuthNotOk(dl); 48436285Sbrian return; 48536285Sbrian } else { 48636285Sbrian dl->bundle->ncp.mp.peer = dl->peer; 48736285Sbrian ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 48836285Sbrian auth_Select(dl->bundle, dl->peer.authname, dl->physical); 48936285Sbrian } 49036285Sbrian 49136285Sbrian fsm_Up(&dl->physical->link.ccp.fsm); 49236285Sbrian fsm_Open(&dl->physical->link.ccp.fsm); 49336285Sbrian datalink_NewState(dl, DATALINK_OPEN); 49436285Sbrian bundle_NewPhase(dl->bundle, PHASE_NETWORK); 49536285Sbrian (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 49636285Sbrian} 49736285Sbrian 49836285Sbrianvoid 49936285Sbriandatalink_AuthNotOk(struct datalink *dl) 50036285Sbrian{ 50136285Sbrian datalink_NewState(dl, DATALINK_LCP); 50236285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 50336285Sbrian} 50436285Sbrian 50536285Sbrianstatic void 50636285Sbriandatalink_LayerDown(void *v, struct fsm *fp) 50736285Sbrian{ 50836285Sbrian /* The given FSM has been told to come down */ 50936285Sbrian struct datalink *dl = (struct datalink *)v; 51036285Sbrian 51136285Sbrian if (fp->proto == PROTO_LCP) { 51236285Sbrian switch (dl->state) { 51336285Sbrian case DATALINK_OPEN: 51436285Sbrian peerid_Init(&dl->peer); 51536285Sbrian fsm_Down(&dl->physical->link.ccp.fsm); 51636285Sbrian fsm_Close(&dl->physical->link.ccp.fsm); 51736928Sbrian datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 51836285Sbrian (*dl->parent->LayerDown)(dl->parent->object, fp); 51936285Sbrian /* fall through */ 52036285Sbrian 52136285Sbrian case DATALINK_AUTH: 52236285Sbrian timer_Stop(&dl->pap.authtimer); 52336285Sbrian timer_Stop(&dl->chap.auth.authtimer); 52436285Sbrian } 52536285Sbrian datalink_NewState(dl, DATALINK_LCP); 52636285Sbrian } 52736285Sbrian} 52836285Sbrian 52936285Sbrianstatic void 53036285Sbriandatalink_LayerFinish(void *v, struct fsm *fp) 53136285Sbrian{ 53236285Sbrian /* The given fsm is now down */ 53336285Sbrian struct datalink *dl = (struct datalink *)v; 53436285Sbrian 53536285Sbrian if (fp->proto == PROTO_LCP) { 53636345Sbrian if (fp->state == ST_STOPPED) 53736345Sbrian fsm_Close(fp); /* back to CLOSED */ 53836345Sbrian fsm_Down(fp); /* Bring us to INITIAL or STARTING */ 53936285Sbrian (*dl->parent->LayerFinish)(dl->parent->object, fp); 54037007Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 54136285Sbrian } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 54236285Sbrian fsm_Open(fp); /* CCP goes to ST_STOPPED */ 54336285Sbrian} 54436285Sbrian 54536285Sbrianstruct datalink * 54636285Sbriandatalink_Create(const char *name, struct bundle *bundle, int type) 54736285Sbrian{ 54836285Sbrian struct datalink *dl; 54936285Sbrian 55036285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 55136285Sbrian if (dl == NULL) 55236285Sbrian return dl; 55336285Sbrian 55436285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 55536285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 55636285Sbrian dl->desc.IsSet = datalink_IsSet; 55736285Sbrian dl->desc.Read = datalink_Read; 55836285Sbrian dl->desc.Write = datalink_Write; 55936285Sbrian 56036285Sbrian dl->state = DATALINK_CLOSED; 56136285Sbrian 56236285Sbrian *dl->cfg.script.dial = '\0'; 56336285Sbrian *dl->cfg.script.login = '\0'; 56436285Sbrian *dl->cfg.script.hangup = '\0'; 56536285Sbrian *dl->cfg.phone.list = '\0'; 56636285Sbrian *dl->phone.list = '\0'; 56736285Sbrian dl->phone.next = NULL; 56836285Sbrian dl->phone.alt = NULL; 56936285Sbrian dl->phone.chosen = "N/A"; 57037007Sbrian dl->stayonline = 0; 57136285Sbrian dl->script.run = 1; 57236285Sbrian dl->script.packetmode = 1; 57336285Sbrian mp_linkInit(&dl->mp); 57436285Sbrian 57536285Sbrian dl->bundle = bundle; 57636285Sbrian dl->next = NULL; 57736285Sbrian 57836285Sbrian memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 57936285Sbrian 58036285Sbrian dl->dial_tries = 0; 58136285Sbrian dl->cfg.dial.max = 1; 58236285Sbrian dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 58336285Sbrian dl->cfg.dial.timeout = DIAL_TIMEOUT; 58436285Sbrian 58536285Sbrian dl->reconnect_tries = 0; 58636285Sbrian dl->cfg.reconnect.max = 0; 58736285Sbrian dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 58836285Sbrian 58936285Sbrian dl->name = strdup(name); 59036285Sbrian peerid_Init(&dl->peer); 59136285Sbrian dl->parent = &bundle->fsm; 59236285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 59336285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 59436285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 59536285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 59636285Sbrian dl->fsmp.object = dl; 59736285Sbrian 59836285Sbrian auth_Init(&dl->pap); 59936285Sbrian auth_Init(&dl->chap.auth); 60036285Sbrian 60136285Sbrian if ((dl->physical = modem_Create(dl, type)) == NULL) { 60236285Sbrian free(dl->name); 60336285Sbrian free(dl); 60436285Sbrian return NULL; 60536285Sbrian } 60636285Sbrian chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 60736285Sbrian 60836285Sbrian log_Printf(LogPHASE, "%s: Created in %s state\n", 60936285Sbrian dl->name, datalink_State(dl)); 61036285Sbrian 61136285Sbrian return dl; 61236285Sbrian} 61336285Sbrian 61436285Sbrianstruct datalink * 61536285Sbriandatalink_Clone(struct datalink *odl, const char *name) 61636285Sbrian{ 61736285Sbrian struct datalink *dl; 61836285Sbrian 61936285Sbrian dl = (struct datalink *)malloc(sizeof(struct datalink)); 62036285Sbrian if (dl == NULL) 62136285Sbrian return dl; 62236285Sbrian 62336285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 62436285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 62536285Sbrian dl->desc.IsSet = datalink_IsSet; 62636285Sbrian dl->desc.Read = datalink_Read; 62736285Sbrian dl->desc.Write = datalink_Write; 62836285Sbrian 62936285Sbrian dl->state = DATALINK_CLOSED; 63036285Sbrian 63136285Sbrian memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 63236285Sbrian mp_linkInit(&dl->mp); 63336285Sbrian *dl->phone.list = '\0'; 63436285Sbrian dl->phone.next = NULL; 63536285Sbrian dl->phone.alt = NULL; 63636285Sbrian dl->phone.chosen = "N/A"; 63736285Sbrian dl->bundle = odl->bundle; 63836285Sbrian dl->next = NULL; 63936285Sbrian memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 64036285Sbrian dl->dial_tries = 0; 64136285Sbrian dl->reconnect_tries = 0; 64236285Sbrian dl->name = strdup(name); 64336285Sbrian peerid_Init(&dl->peer); 64436285Sbrian dl->parent = odl->parent; 64536285Sbrian memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 64636285Sbrian dl->fsmp.object = dl; 64736285Sbrian auth_Init(&dl->pap); 64836285Sbrian dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 64936285Sbrian 65036285Sbrian auth_Init(&dl->chap.auth); 65136285Sbrian dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 65236285Sbrian 65336465Sbrian if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 65436285Sbrian free(dl->name); 65536285Sbrian free(dl); 65636285Sbrian return NULL; 65736285Sbrian } 65836285Sbrian memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 65936285Sbrian memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 66036285Sbrian sizeof dl->physical->link.lcp.cfg); 66136285Sbrian memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 66236285Sbrian sizeof dl->physical->link.ccp.cfg); 66336285Sbrian memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 66436285Sbrian sizeof dl->physical->async.cfg); 66536285Sbrian 66636285Sbrian chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 66736285Sbrian 66836285Sbrian log_Printf(LogPHASE, "%s: Cloned in %s state\n", 66936285Sbrian dl->name, datalink_State(dl)); 67036285Sbrian 67136285Sbrian return dl; 67236285Sbrian} 67336285Sbrian 67436285Sbrianstruct datalink * 67536285Sbriandatalink_Destroy(struct datalink *dl) 67636285Sbrian{ 67736285Sbrian struct datalink *result; 67836285Sbrian 67936285Sbrian if (dl->state != DATALINK_CLOSED) { 68036285Sbrian log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 68136285Sbrian datalink_State(dl)); 68236285Sbrian switch (dl->state) { 68336285Sbrian case DATALINK_HANGUP: 68436285Sbrian case DATALINK_DIAL: 68536285Sbrian case DATALINK_LOGIN: 68636285Sbrian chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 68736285Sbrian break; 68836285Sbrian } 68936285Sbrian } 69036285Sbrian 69136285Sbrian result = dl->next; 69236285Sbrian modem_Destroy(dl->physical); 69336285Sbrian free(dl->name); 69436285Sbrian free(dl); 69536285Sbrian 69636285Sbrian return result; 69736285Sbrian} 69836285Sbrian 69936285Sbrianvoid 70036285Sbriandatalink_Up(struct datalink *dl, int runscripts, int packetmode) 70136285Sbrian{ 70236285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 70336285Sbrian /* Ignore scripts */ 70436285Sbrian runscripts = 0; 70536285Sbrian 70636285Sbrian switch (dl->state) { 70736285Sbrian case DATALINK_CLOSED: 70836285Sbrian if (bundle_Phase(dl->bundle) == PHASE_DEAD || 70936285Sbrian bundle_Phase(dl->bundle) == PHASE_TERMINATE) 71036285Sbrian bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 71136285Sbrian datalink_NewState(dl, DATALINK_OPENING); 71236285Sbrian dl->reconnect_tries = 71336285Sbrian dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 71436285Sbrian dl->dial_tries = dl->cfg.dial.max; 71536285Sbrian dl->script.run = runscripts; 71636285Sbrian dl->script.packetmode = packetmode; 71736285Sbrian break; 71836285Sbrian 71936285Sbrian case DATALINK_OPENING: 72036285Sbrian if (!dl->script.run && runscripts) 72136285Sbrian dl->script.run = 1; 72236285Sbrian /* fall through */ 72336285Sbrian 72436285Sbrian case DATALINK_DIAL: 72536285Sbrian case DATALINK_LOGIN: 72636285Sbrian case DATALINK_READY: 72736285Sbrian if (!dl->script.packetmode && packetmode) { 72836285Sbrian dl->script.packetmode = 1; 72936285Sbrian if (dl->state == DATALINK_READY) 73036285Sbrian datalink_LoginDone(dl); 73136285Sbrian } 73236285Sbrian break; 73336285Sbrian } 73436285Sbrian} 73536285Sbrian 73636285Sbrianvoid 73737007Sbriandatalink_Close(struct datalink *dl, int how) 73836285Sbrian{ 73936285Sbrian /* Please close */ 74036285Sbrian switch (dl->state) { 74136285Sbrian case DATALINK_OPEN: 74236285Sbrian peerid_Init(&dl->peer); 74336285Sbrian fsm_Down(&dl->physical->link.ccp.fsm); 74436285Sbrian fsm_Close(&dl->physical->link.ccp.fsm); 74536285Sbrian /* fall through */ 74636285Sbrian 74736285Sbrian case DATALINK_AUTH: 74836285Sbrian case DATALINK_LCP: 74936285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 75037007Sbrian if (how != CLOSE_NORMAL) { 75136285Sbrian dl->dial_tries = -1; 75236285Sbrian dl->reconnect_tries = 0; 75337007Sbrian if (how == CLOSE_LCP) 75437007Sbrian dl->stayonline = 1; 75536285Sbrian } 75636285Sbrian break; 75736285Sbrian 75836285Sbrian default: 75937007Sbrian datalink_ComeDown(dl, how); 76036285Sbrian } 76136285Sbrian} 76236285Sbrian 76336285Sbrianvoid 76437007Sbriandatalink_Down(struct datalink *dl, int how) 76536285Sbrian{ 76636285Sbrian /* Carrier is lost */ 76736285Sbrian switch (dl->state) { 76836285Sbrian case DATALINK_OPEN: 76936285Sbrian peerid_Init(&dl->peer); 77036285Sbrian fsm_Down(&dl->physical->link.ccp.fsm); 77136285Sbrian fsm_Close(&dl->physical->link.ccp.fsm); 77236285Sbrian /* fall through */ 77336285Sbrian 77436285Sbrian case DATALINK_AUTH: 77536285Sbrian case DATALINK_LCP: 77636345Sbrian if (dl->physical->link.lcp.fsm.state == ST_STOPPED) 77736345Sbrian fsm_Close(&dl->physical->link.lcp.fsm); /* back to CLOSED */ 77836285Sbrian fsm_Down(&dl->physical->link.lcp.fsm); 77937007Sbrian if (how != CLOSE_NORMAL) 78036285Sbrian fsm_Close(&dl->physical->link.lcp.fsm); 78136285Sbrian else 78236285Sbrian fsm_Open(&dl->physical->link.ccp.fsm); 78336285Sbrian /* fall through */ 78436285Sbrian 78536285Sbrian default: 78637007Sbrian datalink_ComeDown(dl, how); 78736285Sbrian } 78836285Sbrian} 78936285Sbrian 79036285Sbrianvoid 79136285Sbriandatalink_StayDown(struct datalink *dl) 79236285Sbrian{ 79336285Sbrian dl->reconnect_tries = 0; 79436285Sbrian} 79536285Sbrian 79637007Sbrianvoid 79737007Sbriandatalink_DontHangup(struct datalink *dl) 79837007Sbrian{ 79937012Sbrian if (dl->state >= DATALINK_LCP) 80037012Sbrian dl->stayonline = 1; 80137007Sbrian} 80237007Sbrian 80336285Sbrianint 80436285Sbriandatalink_Show(struct cmdargs const *arg) 80536285Sbrian{ 80636285Sbrian prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 80736285Sbrian prompt_Printf(arg->prompt, " State: %s\n", 80836285Sbrian datalink_State(arg->cx)); 80936285Sbrian prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 81036285Sbrian arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 81136285Sbrian prompt_Printf(arg->prompt, " Peer name: "); 81236285Sbrian if (*arg->cx->peer.authname) 81336285Sbrian prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 81436285Sbrian else if (arg->cx->state == DATALINK_OPEN) 81536285Sbrian prompt_Printf(arg->prompt, "None requested\n"); 81636285Sbrian else 81736285Sbrian prompt_Printf(arg->prompt, "N/A\n"); 81836285Sbrian prompt_Printf(arg->prompt, " Discriminator: %s\n", 81936285Sbrian mp_Enddisc(arg->cx->peer.enddisc.class, 82036285Sbrian arg->cx->peer.enddisc.address, 82136285Sbrian arg->cx->peer.enddisc.len)); 82236285Sbrian 82336285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 82436285Sbrian prompt_Printf(arg->prompt, " Phone List: %s\n", 82536285Sbrian arg->cx->cfg.phone.list); 82636285Sbrian if (arg->cx->cfg.dial.max) 82736285Sbrian prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 82836285Sbrian arg->cx->cfg.dial.max); 82936285Sbrian else 83036285Sbrian prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 83136285Sbrian if (arg->cx->cfg.dial.next_timeout > 0) 83236285Sbrian prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 83336285Sbrian else 83436285Sbrian prompt_Printf(arg->prompt, "random/"); 83536285Sbrian if (arg->cx->cfg.dial.timeout > 0) 83636285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 83736285Sbrian else 83836285Sbrian prompt_Printf(arg->prompt, "random\n"); 83936285Sbrian prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 84036285Sbrian arg->cx->cfg.reconnect.max); 84136285Sbrian if (arg->cx->cfg.reconnect.timeout > 0) 84236285Sbrian prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 84336285Sbrian else 84436285Sbrian prompt_Printf(arg->prompt, "random\n"); 84536285Sbrian prompt_Printf(arg->prompt, " Dial Script: %s\n", 84636285Sbrian arg->cx->cfg.script.dial); 84736285Sbrian prompt_Printf(arg->prompt, " Login Script: %s\n", 84836285Sbrian arg->cx->cfg.script.login); 84936285Sbrian prompt_Printf(arg->prompt, " Hangup Script: %s\n", 85036285Sbrian arg->cx->cfg.script.hangup); 85136285Sbrian return 0; 85236285Sbrian} 85336285Sbrian 85436285Sbrianint 85536285Sbriandatalink_SetReconnect(struct cmdargs const *arg) 85636285Sbrian{ 85736285Sbrian if (arg->argc == arg->argn+2) { 85836285Sbrian arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 85936285Sbrian arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 86036285Sbrian return 0; 86136285Sbrian } 86236285Sbrian return -1; 86336285Sbrian} 86436285Sbrian 86536285Sbrianint 86636285Sbriandatalink_SetRedial(struct cmdargs const *arg) 86736285Sbrian{ 86836285Sbrian int timeout; 86936285Sbrian int tries; 87036285Sbrian char *dot; 87136285Sbrian 87236285Sbrian if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 87336285Sbrian if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 87436285Sbrian (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 87536285Sbrian arg->cx->cfg.dial.timeout = -1; 87636285Sbrian randinit(); 87736285Sbrian } else { 87836285Sbrian timeout = atoi(arg->argv[arg->argn]); 87936285Sbrian 88036285Sbrian if (timeout >= 0) 88136285Sbrian arg->cx->cfg.dial.timeout = timeout; 88236285Sbrian else { 88336285Sbrian log_Printf(LogWARN, "Invalid redial timeout\n"); 88436285Sbrian return -1; 88536285Sbrian } 88636285Sbrian } 88736285Sbrian 88836285Sbrian dot = strchr(arg->argv[arg->argn], '.'); 88936285Sbrian if (dot) { 89036285Sbrian if (strcasecmp(++dot, "random") == 0) { 89136285Sbrian arg->cx->cfg.dial.next_timeout = -1; 89236285Sbrian randinit(); 89336285Sbrian } else { 89436285Sbrian timeout = atoi(dot); 89536285Sbrian if (timeout >= 0) 89636285Sbrian arg->cx->cfg.dial.next_timeout = timeout; 89736285Sbrian else { 89836285Sbrian log_Printf(LogWARN, "Invalid next redial timeout\n"); 89936285Sbrian return -1; 90036285Sbrian } 90136285Sbrian } 90236285Sbrian } else 90336285Sbrian /* Default next timeout */ 90436285Sbrian arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 90536285Sbrian 90636285Sbrian if (arg->argc == arg->argn+2) { 90736285Sbrian tries = atoi(arg->argv[arg->argn+1]); 90836285Sbrian 90936285Sbrian if (tries >= 0) { 91036285Sbrian arg->cx->cfg.dial.max = tries; 91136285Sbrian } else { 91236285Sbrian log_Printf(LogWARN, "Invalid retry value\n"); 91336285Sbrian return 1; 91436285Sbrian } 91536285Sbrian } 91636285Sbrian return 0; 91736285Sbrian } 91836285Sbrian return -1; 91936285Sbrian} 92036285Sbrian 92136285Sbrianstatic const char *states[] = { 92236285Sbrian "closed", 92336285Sbrian "opening", 92436285Sbrian "hangup", 92536285Sbrian "dial", 92636285Sbrian "login", 92736285Sbrian "ready", 92836285Sbrian "lcp", 92936285Sbrian "auth", 93036285Sbrian "open" 93136285Sbrian}; 93236285Sbrian 93336285Sbrianconst char * 93436285Sbriandatalink_State(struct datalink *dl) 93536285Sbrian{ 93636285Sbrian if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 93736285Sbrian return "unknown"; 93836285Sbrian return states[dl->state]; 93936285Sbrian} 94036285Sbrian 94136285Sbrianstatic void 94236285Sbriandatalink_NewState(struct datalink *dl, int state) 94336285Sbrian{ 94436285Sbrian if (state != dl->state) { 94536285Sbrian if (state >= 0 && state < sizeof states / sizeof states[0]) { 94636285Sbrian log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 94736285Sbrian states[state]); 94836285Sbrian dl->state = state; 94936285Sbrian } else 95036285Sbrian log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 95136285Sbrian } 95236285Sbrian} 95336285Sbrian 95436285Sbrianstruct datalink * 95536285Sbrianiov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 95636285Sbrian int fd) 95736285Sbrian{ 95836285Sbrian struct datalink *dl, *cdl; 95936285Sbrian u_int retry; 96036285Sbrian char *oname; 96136285Sbrian 96236285Sbrian dl = (struct datalink *)iov[(*niov)++].iov_base; 96336285Sbrian dl->name = iov[*niov].iov_base; 96436285Sbrian 96536285Sbrian if (dl->name[DATALINK_MAXNAME-1]) { 96636285Sbrian dl->name[DATALINK_MAXNAME-1] = '\0'; 96736285Sbrian if (strlen(dl->name) == DATALINK_MAXNAME - 1) 96836285Sbrian log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 96936285Sbrian } 97036285Sbrian 97136285Sbrian /* Make sure the name is unique ! */ 97236285Sbrian oname = NULL; 97336285Sbrian do { 97436285Sbrian for (cdl = bundle->links; cdl; cdl = cdl->next) 97536285Sbrian if (!strcasecmp(dl->name, cdl->name)) { 97636285Sbrian if (oname) 97736285Sbrian free(datalink_NextName(dl)); 97836285Sbrian else 97936285Sbrian oname = datalink_NextName(dl); 98036285Sbrian break; /* Keep renaming 'till we have no conflicts */ 98136285Sbrian } 98236285Sbrian } while (cdl); 98336285Sbrian 98436285Sbrian if (oname) { 98536285Sbrian log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 98636285Sbrian free(oname); 98736285Sbrian } else { 98836285Sbrian dl->name = strdup(dl->name); 98936285Sbrian free(iov[*niov].iov_base); 99036285Sbrian } 99136285Sbrian (*niov)++; 99236285Sbrian 99336285Sbrian dl->desc.type = DATALINK_DESCRIPTOR; 99436285Sbrian dl->desc.UpdateSet = datalink_UpdateSet; 99536285Sbrian dl->desc.IsSet = datalink_IsSet; 99636285Sbrian dl->desc.Read = datalink_Read; 99736285Sbrian dl->desc.Write = datalink_Write; 99836285Sbrian 99936285Sbrian mp_linkInit(&dl->mp); 100036285Sbrian *dl->phone.list = '\0'; 100136285Sbrian dl->phone.next = NULL; 100236285Sbrian dl->phone.alt = NULL; 100336285Sbrian dl->phone.chosen = "N/A"; 100436285Sbrian 100536285Sbrian dl->bundle = bundle; 100636285Sbrian dl->next = NULL; 100736285Sbrian memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 100836285Sbrian dl->dial_tries = 0; 100936285Sbrian dl->reconnect_tries = 0; 101036285Sbrian dl->parent = &bundle->fsm; 101136285Sbrian dl->fsmp.LayerStart = datalink_LayerStart; 101236285Sbrian dl->fsmp.LayerUp = datalink_LayerUp; 101336285Sbrian dl->fsmp.LayerDown = datalink_LayerDown; 101436285Sbrian dl->fsmp.LayerFinish = datalink_LayerFinish; 101536285Sbrian dl->fsmp.object = dl; 101636285Sbrian 101736285Sbrian retry = dl->pap.cfg.fsmretry; 101836285Sbrian auth_Init(&dl->pap); 101936285Sbrian dl->pap.cfg.fsmretry = retry; 102036285Sbrian 102136285Sbrian retry = dl->chap.auth.cfg.fsmretry; 102236285Sbrian auth_Init(&dl->chap.auth); 102336285Sbrian dl->chap.auth.cfg.fsmretry = retry; 102436285Sbrian 102536285Sbrian dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 102636285Sbrian 102736285Sbrian if (!dl->physical) { 102836285Sbrian free(dl->name); 102936285Sbrian free(dl); 103036285Sbrian dl = NULL; 103136285Sbrian } else { 103236285Sbrian chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 103336285Sbrian 103436285Sbrian log_Printf(LogPHASE, "%s: Transferred in %s state\n", 103536285Sbrian dl->name, datalink_State(dl)); 103636285Sbrian } 103736285Sbrian 103836285Sbrian return dl; 103936285Sbrian} 104036285Sbrian 104136285Sbrianint 104236450Sbriandatalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 104336450Sbrian pid_t newpid) 104436285Sbrian{ 104536285Sbrian /* If `dl' is NULL, we're allocating before a Fromiov() */ 104636285Sbrian int link_fd; 104736285Sbrian 104836285Sbrian if (dl) { 104936285Sbrian timer_Stop(&dl->dial_timer); 105036285Sbrian timer_Stop(&dl->pap.authtimer); 105136285Sbrian timer_Stop(&dl->chap.auth.authtimer); 105236285Sbrian } 105336285Sbrian 105436285Sbrian if (*niov >= maxiov - 1) { 105536285Sbrian log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 105636285Sbrian if (dl) { 105736285Sbrian free(dl->name); 105836285Sbrian free(dl); 105936285Sbrian } 106036285Sbrian return -1; 106136285Sbrian } 106236285Sbrian 106336285Sbrian iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 106436285Sbrian iov[(*niov)++].iov_len = sizeof *dl; 106536285Sbrian iov[*niov].iov_base = 106636285Sbrian dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 106736285Sbrian iov[(*niov)++].iov_len = DATALINK_MAXNAME; 106836285Sbrian 106936450Sbrian link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 107036285Sbrian 107136285Sbrian if (link_fd == -1 && dl) { 107236285Sbrian free(dl->name); 107336285Sbrian free(dl); 107436285Sbrian } 107536285Sbrian 107636285Sbrian return link_fd; 107736285Sbrian} 107836285Sbrian 107936285Sbrianvoid 108036285Sbriandatalink_Rename(struct datalink *dl, const char *name) 108136285Sbrian{ 108236285Sbrian free(dl->name); 108336285Sbrian dl->physical->link.name = dl->name = strdup(name); 108436285Sbrian} 108536285Sbrian 108636285Sbrianchar * 108736285Sbriandatalink_NextName(struct datalink *dl) 108836285Sbrian{ 108936285Sbrian int f, n; 109036285Sbrian char *name, *oname; 109136285Sbrian 109236285Sbrian n = strlen(dl->name); 109336285Sbrian name = (char *)malloc(n+3); 109436285Sbrian for (f = n - 1; f >= 0; f--) 109536285Sbrian if (!isdigit(dl->name[f])) 109636285Sbrian break; 109736285Sbrian n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 109836285Sbrian sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 109936285Sbrian oname = dl->name; 110036345Sbrian dl->name = name; 110136345Sbrian /* our physical link name isn't updated (it probably isn't created yet) */ 110236285Sbrian return oname; 110336285Sbrian} 110436285Sbrian 110536285Sbrianint 110636285Sbriandatalink_SetMode(struct datalink *dl, int mode) 110736285Sbrian{ 110836285Sbrian if (!physical_SetMode(dl->physical, mode)) 110936285Sbrian return 0; 111036285Sbrian if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 111136285Sbrian dl->script.run = 0; 111236285Sbrian if (dl->physical->type == PHYS_DIRECT) 111336285Sbrian dl->reconnect_tries = 0; 111436465Sbrian if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 111536285Sbrian datalink_Up(dl, 1, 1); 111636285Sbrian return 1; 111736285Sbrian} 1118