diff options
Diffstat (limited to 'usr.sbin/ppp/datalink.c')
-rw-r--r-- | usr.sbin/ppp/datalink.c | 1478 |
1 files changed, 0 insertions, 1478 deletions
diff --git a/usr.sbin/ppp/datalink.c b/usr.sbin/ppp/datalink.c deleted file mode 100644 index d47b11a..0000000 --- a/usr.sbin/ppp/datalink.c +++ /dev/null @@ -1,1478 +0,0 @@ -/*- - * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <ctype.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/uio.h> -#include <termios.h> - -#include "layer.h" -#include "mbuf.h" -#include "log.h" -#include "defs.h" -#include "timer.h" -#include "fsm.h" -#include "descriptor.h" -#include "lqr.h" -#include "hdlc.h" -#include "lcp.h" -#include "async.h" -#include "throughput.h" -#include "ccp.h" -#include "link.h" -#include "physical.h" -#include "iplist.h" -#include "slcompress.h" -#include "ncpaddr.h" -#include "ipcp.h" -#include "filter.h" -#include "mp.h" -#ifndef NORADIUS -#include "radius.h" -#endif -#include "ipv6cp.h" -#include "ncp.h" -#include "bundle.h" -#include "chat.h" -#include "auth.h" -#include "prompt.h" -#include "proto.h" -#include "pap.h" -#include "chap.h" -#include "command.h" -#include "cbcp.h" -#include "datalink.h" - -static void datalink_LoginDone(struct datalink *); -static void datalink_NewState(struct datalink *, unsigned); -static char *datalink_NextName(struct datalink *); - -static void -datalink_OpenTimeout(void *v) -{ - struct datalink *dl = (struct datalink *)v; - - timer_Stop(&dl->dial.timer); - if (dl->state == DATALINK_OPENING) - log_Printf(LogCHAT, "%s: Redial timer expired.\n", dl->name); -} - -static int -datalink_StartDialTimer(struct datalink *dl, int Timeout) -{ - int result = Timeout; - - timer_Stop(&dl->dial.timer); - if (Timeout < 0) - result = (random() % DIAL_TIMEOUT) + 1; - dl->dial.timer.load = result ? result * SECTICKS : 1; - dl->dial.timer.func = datalink_OpenTimeout; - dl->dial.timer.name = "dial"; - dl->dial.timer.arg = dl; - timer_Start(&dl->dial.timer); - if (dl->state == DATALINK_OPENING) - log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", - dl->name, result); - return result; -} - -static void -datalink_HangupDone(struct datalink *dl) -{ - if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && - dl->physical->fd != -1) { - /* Don't close our device if the link is dedicated */ - datalink_LoginDone(dl); - return; - } - - chat_Finish(&dl->chat); - physical_Close(dl->physical); - dl->phone.chosen = "N/A"; - - if (dl->cbcp.required) { - log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); - dl->cfg.callback.opmask = 0; - strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, - sizeof dl->cfg.phone.list - 1); - dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; - dl->phone.alt = dl->phone.next = NULL; - dl->reconnect_tries = dl->cfg.reconnect.max; - dl->dial.tries = dl->cfg.dial.max; - dl->dial.incs = 0; - dl->script.run = 1; - dl->script.packetmode = 1; - if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) - log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); - bundle_LinksRemoved(dl->bundle); - /* if dial.timeout is < 0 (random), we don't override fsm.delay */ - if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) - dl->cbcp.fsm.delay = dl->cfg.dial.timeout; - datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); - cbcp_Down(&dl->cbcp); - datalink_NewState(dl, DATALINK_OPENING); - if (bundle_Phase(dl->bundle) == PHASE_DEAD || - bundle_Phase(dl->bundle) == PHASE_TERMINATE) - bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); - } else if (dl->bundle->CleaningUp || - (dl->physical->type == PHYS_DIRECT) || - ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && - !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { - datalink_NewState(dl, DATALINK_CLOSED); - dl->dial.tries = -1; - dl->dial.incs = 0; - dl->reconnect_tries = 0; - bundle_LinkClosed(dl->bundle, dl); - if (!dl->bundle->CleaningUp && - !(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND))) - datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); - } else { - datalink_NewState(dl, DATALINK_OPENING); - if (bundle_Phase(dl->bundle) == PHASE_DEAD || - bundle_Phase(dl->bundle) == PHASE_TERMINATE) - bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); - if (dl->dial.tries < 0) { - datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); - dl->dial.tries = dl->cfg.dial.max; - dl->dial.incs = 0; - dl->reconnect_tries--; - log_Printf(LogCHAT, "%s: Reconnect try %d of %d\n", - dl->name, dl->cfg.reconnect.max - dl->reconnect_tries, - dl->cfg.reconnect.max); - bundle_Notify(dl->bundle, EX_RECONNECT); - } else { - if (dl->phone.next == NULL) - datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); - else - datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); - bundle_Notify(dl->bundle, EX_REDIAL); - } - } -} - -const char * -datalink_ChoosePhoneNumber(struct datalink *dl) -{ - char *phone; - - if (dl->phone.alt == NULL) { - if (dl->phone.next == NULL) { - strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); - dl->phone.list[sizeof dl->phone.list - 1] = '\0'; - if (*dl->phone.list == '\0') - return ""; - dl->phone.next = dl->phone.list; - } - dl->phone.alt = strsep(&dl->phone.next, ":"); - } - phone = strsep(&dl->phone.alt, "|"); - dl->phone.chosen = *phone ? phone : "[NONE]"; - if (*phone) - log_Printf(LogCHAT, "Phone: %s\n", phone); - return phone; -} - -static void -datalink_LoginDone(struct datalink *dl) -{ - chat_Finish(&dl->chat); - - if (!dl->script.packetmode) { - dl->dial.tries = -1; - dl->dial.incs = 0; - datalink_NewState(dl, DATALINK_READY); - } else if (!physical_Raw(dl->physical)) { - dl->dial.tries = 0; - log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); - if (dl->script.run) { - datalink_NewState(dl, DATALINK_LOGOUT); - if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) - log_Printf(LogWARN, "Invalid logout script\n"); - } else { - physical_StopDeviceTimer(dl->physical); - if (dl->physical->type == PHYS_DEDICATED) - /* force a redial timeout */ - physical_Close(dl->physical); - datalink_HangupDone(dl); - } - } else { - dl->dial.tries = -1; - dl->dial.incs = 0; - - hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); - async_Setup(&dl->physical->async); - - lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? - 0 : dl->physical->link.lcp.cfg.openmode); - ccp_Setup(&dl->physical->link.ccp); - - datalink_NewState(dl, DATALINK_LCP); - fsm_Up(&dl->physical->link.lcp.fsm); - fsm_Open(&dl->physical->link.lcp.fsm); - } -} - -static int -datalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, - int *n) -{ - struct datalink *dl = descriptor2datalink(d); - int result; - - result = 0; - switch (dl->state) { - case DATALINK_CLOSED: - if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND| - PHYS_FOREGROUND|PHYS_DDIAL)) && - !dl->bundle->CleaningUp) - /* - * Our first time in - DEDICATED & DDIAL never come down, and - * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter - * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up() - * and fall through. - */ - datalink_Up(dl, 1, 1); - else - break; - /* FALLTHROUGH */ - - case DATALINK_OPENING: - if (dl->dial.timer.state != TIMER_RUNNING) { - if (--dl->dial.tries < 0) - dl->dial.tries = 0; - if (physical_Open(dl->physical) >= 0) { - log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" - "Type `~?' for help\r\n", dl->name, - dl->physical->name.full); - if (dl->script.run) { - datalink_NewState(dl, DATALINK_DIAL); - if (!chat_Setup(&dl->chat, dl->cfg.script.dial, - *dl->cfg.script.dial ? - datalink_ChoosePhoneNumber(dl) : "")) - log_Printf(LogWARN, "Invalid dial script\n"); - if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && - dl->cfg.dial.max) - log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", - dl->name, dl->cfg.dial.max - dl->dial.tries, - dl->cfg.dial.max); - } else - datalink_NewState(dl, DATALINK_CARRIER); - return datalink_UpdateSet(d, r, w, e, n); - } else { - if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && - dl->cfg.dial.max) - log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n", - dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); - else - log_Printf(LogCHAT, "Failed to open device\n"); - - if (dl->bundle->CleaningUp || - (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && - dl->cfg.dial.max && dl->dial.tries == 0)) { - datalink_NewState(dl, DATALINK_CLOSED); - dl->reconnect_tries = 0; - dl->dial.tries = -1; - log_WritePrompts(dl, "Failed to open %s\n", - dl->physical->name.full); - bundle_LinkClosed(dl->bundle, dl); - } - if (!dl->bundle->CleaningUp) { - int timeout; - - timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); - bundle_Notify(dl->bundle, EX_REDIAL); - log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", - dl->physical->name.full, timeout); - } - } - } - break; - - case DATALINK_CARRIER: - /* Wait for carrier on the device */ - switch (physical_AwaitCarrier(dl->physical)) { - case CARRIER_PENDING: - log_Printf(LogDEBUG, "Waiting for carrier\n"); - return 0; /* A device timer is running to wake us up again */ - - case CARRIER_OK: - if (dl->script.run) { - datalink_NewState(dl, DATALINK_LOGIN); - if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL)) - log_Printf(LogWARN, "Invalid login script\n"); - } else - datalink_LoginDone(dl); - return datalink_UpdateSet(d, r, w, e, n); - - case CARRIER_LOST: - physical_Offline(dl->physical); /* Is this required ? */ - if (dl->script.run) { - datalink_NewState(dl, DATALINK_HANGUP); - if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) - log_Printf(LogWARN, "Invalid hangup script\n"); - return datalink_UpdateSet(d, r, w, e, n); - } else { - datalink_HangupDone(dl); - return 0; /* Maybe bundle_CleanDatalinks() has something to do */ - } - } - - case DATALINK_HANGUP: - case DATALINK_DIAL: - case DATALINK_LOGOUT: - case DATALINK_LOGIN: - result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); - switch (dl->chat.state) { - case CHAT_DONE: - /* script succeeded */ - switch(dl->state) { - case DATALINK_HANGUP: - datalink_HangupDone(dl); - break; - case DATALINK_DIAL: - datalink_NewState(dl, DATALINK_CARRIER); - return datalink_UpdateSet(d, r, w, e, n); - case DATALINK_LOGOUT: - datalink_NewState(dl, DATALINK_HANGUP); - physical_Offline(dl->physical); - if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) - log_Printf(LogWARN, "Invalid hangup script\n"); - return datalink_UpdateSet(d, r, w, e, n); - case DATALINK_LOGIN: - dl->phone.alt = NULL; - datalink_LoginDone(dl); - return datalink_UpdateSet(d, r, w, e, n); - } - break; - case CHAT_FAILED: - /* Going down - script failed */ - log_Printf(LogWARN, "Chat script failed\n"); - switch(dl->state) { - case DATALINK_HANGUP: - datalink_HangupDone(dl); - break; - case DATALINK_DIAL: - case DATALINK_LOGOUT: - case DATALINK_LOGIN: - datalink_NewState(dl, DATALINK_HANGUP); - physical_Offline(dl->physical); - if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) - log_Printf(LogWARN, "Invalid hangup script\n"); - return datalink_UpdateSet(d, r, w, e, n); - } - break; - } - break; - - case DATALINK_READY: - case DATALINK_LCP: - case DATALINK_AUTH: - case DATALINK_CBCP: - case DATALINK_OPEN: - result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + - descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); - break; - } - return result; -} - -int -datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) -{ - return physical_RemoveFromSet(dl->physical, r, w, e); -} - -static int -datalink_IsSet(struct fdescriptor *d, const fd_set *fdset) -{ - struct datalink *dl = descriptor2datalink(d); - - switch (dl->state) { - case DATALINK_CLOSED: - case DATALINK_OPENING: - break; - - case DATALINK_HANGUP: - case DATALINK_DIAL: - case DATALINK_LOGOUT: - case DATALINK_LOGIN: - return descriptor_IsSet(&dl->chat.desc, fdset); - - case DATALINK_READY: - case DATALINK_LCP: - case DATALINK_AUTH: - case DATALINK_CBCP: - case DATALINK_OPEN: - return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : - descriptor_IsSet(&dl->physical->desc, fdset); - } - return 0; -} - -static void -datalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) -{ - struct datalink *dl = descriptor2datalink(d); - - switch (dl->state) { - case DATALINK_CLOSED: - case DATALINK_OPENING: - break; - - case DATALINK_HANGUP: - case DATALINK_DIAL: - case DATALINK_LOGOUT: - case DATALINK_LOGIN: - descriptor_Read(&dl->chat.desc, bundle, fdset); - break; - - case DATALINK_READY: - case DATALINK_LCP: - case DATALINK_AUTH: - case DATALINK_CBCP: - case DATALINK_OPEN: - if (descriptor_IsSet(&dl->chap.desc, fdset)) - descriptor_Read(&dl->chap.desc, bundle, fdset); - if (descriptor_IsSet(&dl->physical->desc, fdset)) - descriptor_Read(&dl->physical->desc, bundle, fdset); - break; - } -} - -static int -datalink_Write(struct fdescriptor *d, struct bundle *bundle, - const fd_set *fdset) -{ - struct datalink *dl = descriptor2datalink(d); - int result = 0; - - switch (dl->state) { - case DATALINK_CLOSED: - case DATALINK_OPENING: - break; - - case DATALINK_HANGUP: - case DATALINK_DIAL: - case DATALINK_LOGOUT: - case DATALINK_LOGIN: - if ((result = descriptor_Write(&dl->chat.desc, bundle, fdset)) == -1) { - datalink_ComeDown(dl, CLOSE_NORMAL); - result = 0; - } - break; - - case DATALINK_READY: - case DATALINK_LCP: - case DATALINK_AUTH: - case DATALINK_CBCP: - case DATALINK_OPEN: - if (descriptor_IsSet(&dl->chap.desc, fdset)) - switch (descriptor_Write(&dl->chap.desc, bundle, fdset)) { - case -1: - datalink_ComeDown(dl, CLOSE_NORMAL); - break; - case 1: - result++; - } - if (descriptor_IsSet(&dl->physical->desc, fdset)) - switch (descriptor_Write(&dl->physical->desc, bundle, fdset)) { - case -1: - datalink_ComeDown(dl, CLOSE_NORMAL); - break; - case 1: - result++; - } - break; - } - - return result; -} - -void -datalink_ComeDown(struct datalink *dl, int how) -{ - int stayonline; - - if (how == CLOSE_LCP) - datalink_DontHangup(dl); - else if (how == CLOSE_STAYDOWN) - datalink_StayDown(dl); - - stayonline = dl->stayonline; - dl->stayonline = 0; - - if (dl->state >= DATALINK_READY && stayonline) { - physical_StopDeviceTimer(dl->physical); - datalink_NewState(dl, DATALINK_READY); - } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { - physical_Offline(dl->physical); - if (dl->script.run && dl->state != DATALINK_OPENING) { - if (dl->state == DATALINK_LOGOUT) { - datalink_NewState(dl, DATALINK_HANGUP); - if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL)) - log_Printf(LogWARN, "Invalid hangup script\n"); - } else { - datalink_NewState(dl, DATALINK_LOGOUT); - if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL)) - log_Printf(LogWARN, "Invalid logout script\n"); - } - } else - datalink_HangupDone(dl); - } -} - -static void -datalink_LayerStart(void *v, struct fsm *fp) -{ - /* The given FSM is about to start up ! */ - struct datalink *dl = (struct datalink *)v; - - if (fp->proto == PROTO_LCP) - (*dl->parent->LayerStart)(dl->parent->object, fp); -} - -static void -datalink_LayerUp(void *v, struct fsm *fp) -{ - /* The given fsm is now up */ - struct datalink *dl = (struct datalink *)v; - struct lcp *lcp = &dl->physical->link.lcp; - - if (fp->proto == PROTO_LCP) { - datalink_GotAuthname(dl, ""); - lcp->auth_ineed = lcp->want_auth; - lcp->auth_iwait = lcp->his_auth; - if (lcp->his_auth || lcp->want_auth) { - if (bundle_Phase(dl->bundle) != PHASE_NETWORK) - bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); - log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, - Auth2Nam(lcp->his_auth, lcp->his_authtype), - Auth2Nam(lcp->want_auth, lcp->want_authtype)); - if (lcp->his_auth == PROTO_PAP) - auth_StartReq(&dl->pap); - if (lcp->want_auth == PROTO_CHAP) - auth_StartReq(&dl->chap.auth); - } else - datalink_AuthOk(dl); - } else if (fp->proto == PROTO_CCP) - (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.ccp.fsm); -} - -static void -datalink_AuthReInit(struct datalink *dl) -{ - auth_StopTimer(&dl->pap); - auth_StopTimer(&dl->chap.auth); - chap_ReInit(&dl->chap); -} - -void -datalink_GotAuthname(struct datalink *dl, const char *name) -{ - strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); - dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; -} - -void -datalink_NCPUp(struct datalink *dl) -{ - int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); - - if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { - /* we've authenticated in multilink mode ! */ - switch (mp_Up(&dl->bundle->ncp.mp, dl)) { - case MP_LINKSENT: - /* We've handed the link off to another ppp (well, we will soon) ! */ - return; - case MP_UP: - /* First link in the bundle */ - auth_Select(dl->bundle, dl->peer.authname); - bundle_CalculateBandwidth(dl->bundle); - /* FALLTHROUGH */ - case MP_ADDED: - /* We're in multilink mode ! */ - dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ - bundle_CalculateBandwidth(dl->bundle); - break; - case MP_FAILED: - datalink_AuthNotOk(dl); - return; - } - } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { - log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); - datalink_NewState(dl, DATALINK_OPEN); - bundle_CalculateBandwidth(dl->bundle); - (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); - return; - } else { - dl->bundle->ncp.mp.peer = dl->peer; - ncp_SetLink(&dl->bundle->ncp, &dl->physical->link); - auth_Select(dl->bundle, dl->peer.authname); - } - - if (ccpok) { - fsm_Up(&dl->physical->link.ccp.fsm); - fsm_Open(&dl->physical->link.ccp.fsm); - } - datalink_NewState(dl, DATALINK_OPEN); - bundle_NewPhase(dl->bundle, PHASE_NETWORK); - (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); -} - -void -datalink_CBCPComplete(struct datalink *dl) -{ - datalink_NewState(dl, DATALINK_LCP); - datalink_AuthReInit(dl); - fsm_Close(&dl->physical->link.lcp.fsm); -} - -void -datalink_CBCPFailed(struct datalink *dl) -{ - cbcp_Down(&dl->cbcp); - datalink_CBCPComplete(dl); -} - -void -datalink_AuthOk(struct datalink *dl) -{ - if ((dl->physical->link.lcp.his_callback.opmask & - CALLBACK_BIT(CALLBACK_CBCP) || - dl->physical->link.lcp.want_callback.opmask & - CALLBACK_BIT(CALLBACK_CBCP)) && - !(dl->physical->link.lcp.want_callback.opmask & - CALLBACK_BIT(CALLBACK_AUTH))) { - /* We must have agreed CBCP if AUTH isn't there any more */ - datalink_NewState(dl, DATALINK_CBCP); - cbcp_Up(&dl->cbcp); - } else if (dl->physical->link.lcp.want_callback.opmask) { - /* It's not CBCP */ - log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); - datalink_NewState(dl, DATALINK_LCP); - datalink_AuthReInit(dl); - fsm_Close(&dl->physical->link.lcp.fsm); - } else - switch (dl->physical->link.lcp.his_callback.opmask) { - case 0: - datalink_NCPUp(dl); - break; - - case CALLBACK_BIT(CALLBACK_AUTH): - auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, - sizeof dl->cbcp.fsm.phone); - if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { - log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, - dl->peer.authname); - *dl->cbcp.fsm.phone = '\0'; - } else { - char *ptr = strchr(dl->cbcp.fsm.phone, ','); - if (ptr) - *ptr = '\0'; /* Call back on the first number */ - log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, - dl->cbcp.fsm.phone); - dl->cbcp.required = 1; - } - dl->cbcp.fsm.delay = 0; - datalink_NewState(dl, DATALINK_LCP); - datalink_AuthReInit(dl); - fsm_Close(&dl->physical->link.lcp.fsm); - break; - - case CALLBACK_BIT(CALLBACK_E164): - strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, - sizeof dl->cbcp.fsm.phone - 1); - dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; - log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, - dl->cbcp.fsm.phone); - dl->cbcp.required = 1; - dl->cbcp.fsm.delay = 0; - datalink_NewState(dl, DATALINK_LCP); - datalink_AuthReInit(dl); - fsm_Close(&dl->physical->link.lcp.fsm); - break; - - default: - log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", - dl->name); - datalink_NewState(dl, DATALINK_LCP); - datalink_AuthReInit(dl); - fsm_Close(&dl->physical->link.lcp.fsm); - break; - } -} - -void -datalink_AuthNotOk(struct datalink *dl) -{ - datalink_NewState(dl, DATALINK_LCP); - datalink_AuthReInit(dl); - fsm_Close(&dl->physical->link.lcp.fsm); -} - -static void -datalink_LayerDown(void *v, struct fsm *fp) -{ - /* The given FSM has been told to come down */ - struct datalink *dl = (struct datalink *)v; - - if (fp->proto == PROTO_LCP) { - switch (dl->state) { - case DATALINK_OPEN: - peerid_Init(&dl->peer); - fsm2initial(&dl->physical->link.ccp.fsm); - datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ - (*dl->parent->LayerDown)(dl->parent->object, fp); - /* FALLTHROUGH (just in case) */ - - case DATALINK_CBCP: - if (!dl->cbcp.required) - cbcp_Down(&dl->cbcp); - /* FALLTHROUGH (just in case) */ - - case DATALINK_AUTH: - timer_Stop(&dl->pap.authtimer); - timer_Stop(&dl->chap.auth.authtimer); - } - datalink_NewState(dl, DATALINK_LCP); - datalink_AuthReInit(dl); - } -} - -static void -datalink_LayerFinish(void *v, struct fsm *fp) -{ - /* The given fsm is now down */ - struct datalink *dl = (struct datalink *)v; - - if (fp->proto == PROTO_LCP) { - fsm2initial(fp); - (*dl->parent->LayerFinish)(dl->parent->object, fp); - datalink_ComeDown(dl, CLOSE_NORMAL); - } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) - fsm_Open(fp); /* CCP goes to ST_STOPPED */ -} - -struct datalink * -datalink_Create(const char *name, struct bundle *bundle, int type) -{ - struct datalink *dl; - - dl = (struct datalink *)malloc(sizeof(struct datalink)); - if (dl == NULL) - return dl; - - dl->desc.type = DATALINK_DESCRIPTOR; - dl->desc.UpdateSet = datalink_UpdateSet; - dl->desc.IsSet = datalink_IsSet; - dl->desc.Read = datalink_Read; - dl->desc.Write = datalink_Write; - - dl->state = DATALINK_CLOSED; - - *dl->cfg.script.dial = '\0'; - *dl->cfg.script.login = '\0'; - *dl->cfg.script.logout = '\0'; - *dl->cfg.script.hangup = '\0'; - *dl->cfg.phone.list = '\0'; - *dl->phone.list = '\0'; - dl->phone.next = NULL; - dl->phone.alt = NULL; - dl->phone.chosen = "N/A"; - dl->stayonline = 0; - dl->script.run = 1; - dl->script.packetmode = 1; - mp_linkInit(&dl->mp); - - dl->bundle = bundle; - dl->next = NULL; - - memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); - - dl->dial.tries = 0; - dl->cfg.dial.max = 1; - dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; - dl->cfg.dial.timeout = DIAL_TIMEOUT; - dl->cfg.dial.inc = 0; - dl->cfg.dial.maxinc = 10; - - dl->reconnect_tries = 0; - dl->cfg.reconnect.max = 0; - dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; - - dl->cfg.callback.opmask = 0; - dl->cfg.cbcp.delay = 0; - *dl->cfg.cbcp.phone = '\0'; - dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; - - dl->name = strdup(name); - peerid_Init(&dl->peer); - dl->parent = &bundle->fsm; - dl->fsmp.LayerStart = datalink_LayerStart; - dl->fsmp.LayerUp = datalink_LayerUp; - dl->fsmp.LayerDown = datalink_LayerDown; - dl->fsmp.LayerFinish = datalink_LayerFinish; - dl->fsmp.object = dl; - - if ((dl->physical = physical_Create(dl, type)) == NULL) { - free(dl->name); - free(dl); - return NULL; - } - - pap_Init(&dl->pap, dl->physical); - chap_Init(&dl->chap, dl->physical); - cbcp_Init(&dl->cbcp, dl->physical); - - memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ - chat_Init(&dl->chat, dl->physical); - - log_Printf(LogPHASE, "%s: Created in %s state\n", - dl->name, datalink_State(dl)); - - return dl; -} - -struct datalink * -datalink_Clone(struct datalink *odl, const char *name) -{ - struct datalink *dl; - - dl = (struct datalink *)malloc(sizeof(struct datalink)); - if (dl == NULL) - return dl; - - dl->desc.type = DATALINK_DESCRIPTOR; - dl->desc.UpdateSet = datalink_UpdateSet; - dl->desc.IsSet = datalink_IsSet; - dl->desc.Read = datalink_Read; - dl->desc.Write = datalink_Write; - - dl->state = DATALINK_CLOSED; - - memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); - mp_linkInit(&dl->mp); - *dl->phone.list = '\0'; - dl->phone.next = NULL; - dl->phone.alt = NULL; - dl->phone.chosen = "N/A"; - dl->bundle = odl->bundle; - dl->next = NULL; - memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); - dl->dial.tries = 0; - dl->reconnect_tries = 0; - dl->name = strdup(name); - peerid_Init(&dl->peer); - dl->parent = odl->parent; - memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); - dl->fsmp.object = dl; - - if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) { - free(dl->name); - free(dl); - return NULL; - } - pap_Init(&dl->pap, dl->physical); - dl->pap.cfg = odl->pap.cfg; - - chap_Init(&dl->chap, dl->physical); - dl->chap.auth.cfg = odl->chap.auth.cfg; - - memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); - memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, - sizeof dl->physical->link.lcp.cfg); - memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, - sizeof dl->physical->link.ccp.cfg); - memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, - sizeof dl->physical->async.cfg); - - cbcp_Init(&dl->cbcp, dl->physical); - - memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ - chat_Init(&dl->chat, dl->physical); - - log_Printf(LogPHASE, "%s: Cloned in %s state\n", - dl->name, datalink_State(dl)); - - return dl; -} - -struct datalink * -datalink_Destroy(struct datalink *dl) -{ - struct datalink *result; - - if (dl->state != DATALINK_CLOSED) { - log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", - datalink_State(dl)); - switch (dl->state) { - case DATALINK_HANGUP: - case DATALINK_DIAL: - case DATALINK_LOGIN: - chat_Finish(&dl->chat); /* Gotta blat the timers ! */ - break; - } - } - - chat_Destroy(&dl->chat); - timer_Stop(&dl->dial.timer); - result = dl->next; - physical_Destroy(dl->physical); - free(dl->name); - free(dl); - - return result; -} - -void -datalink_Up(struct datalink *dl, int runscripts, int packetmode) -{ - if (!Enabled(dl->bundle, OPT_FORCE_SCRIPTS) && - (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))) - /* Ignore scripts */ - runscripts = 0; - - switch (dl->state) { - case DATALINK_CLOSED: - if (bundle_Phase(dl->bundle) == PHASE_DEAD || - bundle_Phase(dl->bundle) == PHASE_TERMINATE) - bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); - datalink_NewState(dl, DATALINK_OPENING); - dl->reconnect_tries = - dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; - dl->dial.tries = dl->cfg.dial.max; - dl->script.run = runscripts; - dl->script.packetmode = packetmode; - break; - - case DATALINK_OPENING: - if (!dl->script.run && runscripts) - dl->script.run = 1; - /* FALLTHROUGH */ - - case DATALINK_DIAL: - case DATALINK_LOGIN: - case DATALINK_READY: - if (!dl->script.packetmode && packetmode) { - dl->script.packetmode = 1; - if (dl->state == DATALINK_READY) { - dl->script.run = 0; - datalink_NewState(dl, DATALINK_CARRIER); - } - } - break; - } -} - -void -datalink_Close(struct datalink *dl, int how) -{ - /* Please close */ - switch (dl->state) { - case DATALINK_OPEN: - peerid_Init(&dl->peer); - fsm2initial(&dl->physical->link.ccp.fsm); - /* FALLTHROUGH */ - - case DATALINK_CBCP: - case DATALINK_AUTH: - case DATALINK_LCP: - datalink_AuthReInit(dl); - if (how == CLOSE_LCP) - datalink_DontHangup(dl); - else if (how == CLOSE_STAYDOWN) - datalink_StayDown(dl); - fsm_Close(&dl->physical->link.lcp.fsm); - break; - - default: - datalink_ComeDown(dl, how); - } -} - -void -datalink_Down(struct datalink *dl, int how) -{ - /* Carrier is lost */ - switch (dl->state) { - case DATALINK_OPEN: - peerid_Init(&dl->peer); - fsm2initial(&dl->physical->link.ccp.fsm); - /* FALLTHROUGH */ - - case DATALINK_CBCP: - case DATALINK_AUTH: - case DATALINK_LCP: - fsm2initial(&dl->physical->link.lcp.fsm); - if (dl->state == DATALINK_OPENING) - return; /* we're doing a callback... */ - /* FALLTHROUGH */ - - default: - datalink_ComeDown(dl, how); - } -} - -void -datalink_StayDown(struct datalink *dl) -{ - dl->dial.tries = -1; - dl->reconnect_tries = 0; - dl->stayonline = 0; -} - -void -datalink_DontHangup(struct datalink *dl) -{ - dl->dial.tries = -1; - dl->reconnect_tries = 0; - dl->stayonline = dl->state >= DATALINK_LCP ? 1 : 0; -} - -int -datalink_Show(struct cmdargs const *arg) -{ - prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); - prompt_Printf(arg->prompt, " State: %s\n", - datalink_State(arg->cx)); - prompt_Printf(arg->prompt, " Peer name: "); - if (*arg->cx->peer.authname) - prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); - else if (arg->cx->state == DATALINK_OPEN) - prompt_Printf(arg->prompt, "None requested\n"); - else - prompt_Printf(arg->prompt, "N/A\n"); - prompt_Printf(arg->prompt, " Discriminator: %s\n", - mp_Enddisc(arg->cx->peer.enddisc.class, - arg->cx->peer.enddisc.address, - arg->cx->peer.enddisc.len)); - - prompt_Printf(arg->prompt, "\nDefaults:\n"); - prompt_Printf(arg->prompt, " Phone List: %s\n", - arg->cx->cfg.phone.list); - if (arg->cx->cfg.dial.max) - prompt_Printf(arg->prompt, " Dial tries: %d, delay ", - arg->cx->cfg.dial.max); - else - prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); - if (arg->cx->cfg.dial.next_timeout >= 0) - prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); - else - prompt_Printf(arg->prompt, "random/"); - if (arg->cx->cfg.dial.timeout >= 0) - prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); - else - prompt_Printf(arg->prompt, "random\n"); - prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", - arg->cx->cfg.reconnect.max); - if (arg->cx->cfg.reconnect.timeout > 0) - prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); - else - prompt_Printf(arg->prompt, "random\n"); - prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == - PHYS_DIRECT ? "accepted: " : "requested:"); - if (!arg->cx->cfg.callback.opmask) - prompt_Printf(arg->prompt, "none\n"); - else { - int comma = 0; - - if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { - prompt_Printf(arg->prompt, "none"); - comma = 1; - } - if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { - prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); - comma = 1; - } - if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { - prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); - if (arg->cx->physical->type != PHYS_DIRECT) - prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); - comma = 1; - } - if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { - prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); - prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", - arg->cx->cfg.cbcp.delay); - prompt_Printf(arg->prompt, " phone: "); - if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { - if (arg->cx->physical->type & PHYS_DIRECT) - prompt_Printf(arg->prompt, "Caller decides\n"); - else - prompt_Printf(arg->prompt, "Dialback server decides\n"); - } else - prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); - prompt_Printf(arg->prompt, " timeout: %lds\n", - arg->cx->cfg.cbcp.fsmretry); - } else - prompt_Printf(arg->prompt, "\n"); - } - - prompt_Printf(arg->prompt, " Dial Script: %s\n", - arg->cx->cfg.script.dial); - prompt_Printf(arg->prompt, " Login Script: %s\n", - arg->cx->cfg.script.login); - prompt_Printf(arg->prompt, " Logout Script: %s\n", - arg->cx->cfg.script.logout); - prompt_Printf(arg->prompt, " Hangup Script: %s\n", - arg->cx->cfg.script.hangup); - return 0; -} - -int -datalink_SetReconnect(struct cmdargs const *arg) -{ - if (arg->argc == arg->argn+2) { - arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); - arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); - return 0; - } - return -1; -} - -int -datalink_SetRedial(struct cmdargs const *arg) -{ - const char *sep, *osep; - int timeout, inc, maxinc, tries; - - if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { - if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && - (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { - arg->cx->cfg.dial.timeout = -1; - randinit(); - } else { - timeout = atoi(arg->argv[arg->argn]); - - if (timeout >= 0) - arg->cx->cfg.dial.timeout = timeout; - else { - log_Printf(LogWARN, "Invalid redial timeout\n"); - return -1; - } - } - - sep = strchr(arg->argv[arg->argn], '+'); - if (sep) { - inc = atoi(++sep); - osep = sep; - if (inc >= 0) - arg->cx->cfg.dial.inc = inc; - else { - log_Printf(LogWARN, "Invalid timeout increment\n"); - return -1; - } - sep = strchr(sep, '-'); - if (sep) { - maxinc = atoi(++sep); - if (maxinc >= 0) - arg->cx->cfg.dial.maxinc = maxinc; - else { - log_Printf(LogWARN, "Invalid maximum timeout increments\n"); - return -1; - } - } else { - /* Default timeout increment */ - arg->cx->cfg.dial.maxinc = 10; - sep = osep; - } - } else { - /* Default timeout increment & max increment */ - arg->cx->cfg.dial.inc = 0; - arg->cx->cfg.dial.maxinc = 10; - sep = arg->argv[arg->argn]; - } - - sep = strchr(sep, '.'); - if (sep) { - if (strcasecmp(++sep, "random") == 0) { - arg->cx->cfg.dial.next_timeout = -1; - randinit(); - } else { - timeout = atoi(sep); - if (timeout >= 0) - arg->cx->cfg.dial.next_timeout = timeout; - else { - log_Printf(LogWARN, "Invalid next redial timeout\n"); - return -1; - } - } - } else - /* Default next timeout */ - arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; - - if (arg->argc == arg->argn+2) { - tries = atoi(arg->argv[arg->argn+1]); - - if (tries >= 0) { - arg->cx->cfg.dial.max = tries; - } else { - log_Printf(LogWARN, "Invalid retry value\n"); - return 1; - } - } - return 0; - } - - return -1; -} - -static const char * const states[] = { - "closed", - "opening", - "hangup", - "dial", - "carrier", - "logout", - "login", - "ready", - "lcp", - "auth", - "cbcp", - "open" -}; - -const char * -datalink_State(struct datalink *dl) -{ - if (dl->state >= sizeof states / sizeof states[0]) - return "unknown"; - return states[dl->state]; -} - -static void -datalink_NewState(struct datalink *dl, unsigned state) -{ - if (state != dl->state) { - if (state < sizeof states / sizeof states[0]) { - log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), - states[state]); - dl->state = state; - } else - log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); - } -} - -struct datalink * -iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, - int fd, int *auxfd, int *nauxfd) -{ - struct datalink *dl, *cdl; - struct fsm_retry copy; - char *oname, *pname; - - dl = (struct datalink *)iov[(*niov)++].iov_base; - dl->name = iov[*niov].iov_base; - - if (dl->name[DATALINK_MAXNAME-1]) { - dl->name[DATALINK_MAXNAME-1] = '\0'; - if (strlen(dl->name) == DATALINK_MAXNAME - 1) - log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); - } - - /* Make sure the name is unique ! */ - oname = NULL; - do { - for (cdl = bundle->links; cdl; cdl = cdl->next) - if (!strcasecmp(dl->name, cdl->name)) { - if ((pname = datalink_NextName(dl)) == NULL) { - for ((*niov)--; *niov < maxiov; (*niov)++) - free(iov[*niov].iov_base); - return NULL; - } else if (oname) - free(pname); - else - oname = pname; - break; /* Keep renaming 'till we have no conflicts */ - } - } while (cdl); - - if (oname) { - log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); - free(oname); - } else { - dl->name = strdup(dl->name); - free(iov[*niov].iov_base); - } - (*niov)++; - - dl->desc.type = DATALINK_DESCRIPTOR; - dl->desc.UpdateSet = datalink_UpdateSet; - dl->desc.IsSet = datalink_IsSet; - dl->desc.Read = datalink_Read; - dl->desc.Write = datalink_Write; - - mp_linkInit(&dl->mp); - *dl->phone.list = '\0'; - dl->phone.next = NULL; - dl->phone.alt = NULL; - dl->phone.chosen = "N/A"; - - dl->bundle = bundle; - dl->next = NULL; - memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); - dl->dial.tries = 0; - dl->reconnect_tries = 0; - dl->parent = &bundle->fsm; - dl->fsmp.LayerStart = datalink_LayerStart; - dl->fsmp.LayerUp = datalink_LayerUp; - dl->fsmp.LayerDown = datalink_LayerDown; - dl->fsmp.LayerFinish = datalink_LayerFinish; - dl->fsmp.object = dl; - - dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd); - - if (!dl->physical) { - free(dl->name); - free(dl); - dl = NULL; - } else { - copy = dl->pap.cfg.fsm; - pap_Init(&dl->pap, dl->physical); - dl->pap.cfg.fsm = copy; - - copy = dl->chap.auth.cfg.fsm; - chap_Init(&dl->chap, dl->physical); - dl->chap.auth.cfg.fsm = copy; - - cbcp_Init(&dl->cbcp, dl->physical); - - memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */ - chat_Init(&dl->chat, dl->physical); - - log_Printf(LogPHASE, "%s: Transferred in %s state\n", - dl->name, datalink_State(dl)); - } - - return dl; -} - -int -datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, - int *auxfd, int *nauxfd) -{ - /* If `dl' is NULL, we're allocating before a Fromiov() */ - int link_fd; - - if (dl) { - timer_Stop(&dl->dial.timer); - /* The following is purely for the sake of paranoia */ - cbcp_Down(&dl->cbcp); - timer_Stop(&dl->pap.authtimer); - timer_Stop(&dl->chap.auth.authtimer); - } - - if (*niov >= maxiov - 1) { - log_Printf(LogERROR, "Toiov: No room for datalink !\n"); - if (dl) { - free(dl->name); - free(dl); - } - return -1; - } - - iov[*niov].iov_base = (void *)dl; - iov[(*niov)++].iov_len = sizeof *dl; - iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL; - iov[(*niov)++].iov_len = DATALINK_MAXNAME; - - link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd, - nauxfd); - - if (link_fd == -1 && dl) { - free(dl->name); - free(dl); - } - - return link_fd; -} - -void -datalink_Rename(struct datalink *dl, const char *name) -{ - free(dl->name); - dl->physical->link.name = dl->name = strdup(name); -} - -static char * -datalink_NextName(struct datalink *dl) -{ - int f, n; - char *name, *oname; - - n = strlen(dl->name); - if ((name = (char *)malloc(n+3)) == NULL) { - log_Printf(LogERROR, "datalink_NextName: Out of memory !\n"); - return NULL; - } - for (f = n - 1; f >= 0; f--) - if (!isdigit(dl->name[f])) - break; - n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); - sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); - oname = dl->name; - dl->name = name; - /* our physical link name isn't updated (it probably isn't created yet) */ - return oname; -} - -int -datalink_SetMode(struct datalink *dl, int mode) -{ - if (!physical_SetMode(dl->physical, mode)) - return 0; - if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) - dl->script.run = 0; - if (dl->physical->type == PHYS_DIRECT) - dl->reconnect_tries = 0; - if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) && - dl->state <= DATALINK_READY) - datalink_Up(dl, 1, 1); - return 1; -} - -int -datalink_GetDialTimeout(struct datalink *dl) -{ - int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; - - if (dl->dial.incs < dl->cfg.dial.maxinc) - dl->dial.incs++; - - return result; -} |