1998-05-21 21:49:08 +00:00
|
|
|
/*-
|
|
|
|
* 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.
|
|
|
|
*
|
1999-08-28 01:35:59 +00:00
|
|
|
* $FreeBSD$
|
1998-05-21 21:49:08 +00:00
|
|
|
*/
|
|
|
|
|
1999-01-28 01:56:34 +00:00
|
|
|
#include <sys/param.h>
|
1998-05-21 21:49:08 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
2001-08-14 16:05:52 +00:00
|
|
|
#include <sys/socket.h>
|
1998-05-21 21:49:08 +00:00
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
|
|
#include <ctype.h>
|
2002-08-27 20:11:58 +00:00
|
|
|
#include <stdarg.h>
|
1998-05-21 21:49:08 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#include <termios.h>
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "layer.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "mbuf.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "defs.h"
|
|
|
|
#include "timer.h"
|
|
|
|
#include "fsm.h"
|
|
|
|
#include "descriptor.h"
|
|
|
|
#include "lqr.h"
|
|
|
|
#include "hdlc.h"
|
2000-07-19 02:10:35 +00:00
|
|
|
#include "lcp.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "async.h"
|
|
|
|
#include "throughput.h"
|
|
|
|
#include "ccp.h"
|
|
|
|
#include "link.h"
|
|
|
|
#include "physical.h"
|
|
|
|
#include "iplist.h"
|
|
|
|
#include "slcompress.h"
|
2001-08-14 16:05:52 +00:00
|
|
|
#include "ncpaddr.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "ipcp.h"
|
|
|
|
#include "filter.h"
|
|
|
|
#include "mp.h"
|
1999-01-28 01:56:34 +00:00
|
|
|
#ifndef NORADIUS
|
|
|
|
#include "radius.h"
|
|
|
|
#endif
|
2001-08-14 16:05:52 +00:00
|
|
|
#include "ipv6cp.h"
|
|
|
|
#include "ncp.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "bundle.h"
|
|
|
|
#include "chat.h"
|
|
|
|
#include "auth.h"
|
|
|
|
#include "prompt.h"
|
1999-05-08 11:07:56 +00:00
|
|
|
#include "proto.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "pap.h"
|
|
|
|
#include "chap.h"
|
|
|
|
#include "command.h"
|
1998-08-07 18:42:51 +00:00
|
|
|
#include "cbcp.h"
|
1998-05-21 21:49:08 +00:00
|
|
|
#include "datalink.h"
|
|
|
|
|
|
|
|
static void datalink_LoginDone(struct datalink *);
|
2004-09-05 01:46:52 +00:00
|
|
|
static void datalink_NewState(struct datalink *, unsigned);
|
2004-10-11 09:45:58 +00:00
|
|
|
static char *datalink_NextName(struct datalink *);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
datalink_OpenTimeout(void *v)
|
|
|
|
{
|
|
|
|
struct datalink *dl = (struct datalink *)v;
|
|
|
|
|
1999-03-04 17:42:15 +00:00
|
|
|
timer_Stop(&dl->dial.timer);
|
1998-05-21 21:49:08 +00:00
|
|
|
if (dl->state == DATALINK_OPENING)
|
2000-04-07 23:46:14 +00:00
|
|
|
log_Printf(LogCHAT, "%s: Redial timer expired.\n", dl->name);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
1999-02-25 12:00:04 +00:00
|
|
|
static int
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_StartDialTimer(struct datalink *dl, int Timeout)
|
|
|
|
{
|
1999-02-25 12:00:04 +00:00
|
|
|
int result = Timeout;
|
|
|
|
|
1999-03-04 17:42:15 +00:00
|
|
|
timer_Stop(&dl->dial.timer);
|
2001-10-23 13:52:19 +00:00
|
|
|
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);
|
1999-02-25 12:00:04 +00:00
|
|
|
return result;
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
datalink_HangupDone(struct datalink *dl)
|
|
|
|
{
|
|
|
|
if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp &&
|
1999-05-08 11:07:56 +00:00
|
|
|
dl->physical->fd != -1) {
|
|
|
|
/* Don't close our device if the link is dedicated */
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_LoginDone(dl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-12-03 06:33:10 +00:00
|
|
|
chat_Finish(&dl->chat);
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Close(dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->phone.chosen = "N/A";
|
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
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;
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = dl->cfg.dial.max;
|
|
|
|
dl->dial.incs = 0;
|
1998-08-07 18:42:51 +00:00
|
|
|
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);
|
1999-03-04 17:42:15 +00:00
|
|
|
/* if dial.timeout is < 0 (random), we don't override fsm.delay */
|
1998-08-07 18:42:51 +00:00
|
|
|
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);
|
1999-10-21 00:19:33 +00:00
|
|
|
if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
|
|
|
|
bundle_Phase(dl->bundle) == PHASE_TERMINATE)
|
1999-04-06 14:48:10 +00:00
|
|
|
bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
|
1998-08-07 18:42:51 +00:00
|
|
|
} else if (dl->bundle->CleaningUp ||
|
1998-05-21 21:49:08 +00:00
|
|
|
(dl->physical->type == PHYS_DIRECT) ||
|
1999-03-04 17:42:15 +00:00
|
|
|
((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) &&
|
1998-05-29 18:32:11 +00:00
|
|
|
!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) {
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_NewState(dl, DATALINK_CLOSED);
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = -1;
|
|
|
|
dl->dial.incs = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->reconnect_tries = 0;
|
|
|
|
bundle_LinkClosed(dl->bundle, dl);
|
2000-03-22 03:01:56 +00:00
|
|
|
if (!dl->bundle->CleaningUp &&
|
|
|
|
!(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)))
|
1999-03-04 17:42:15 +00:00
|
|
|
datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
|
1998-05-21 21:49:08 +00:00
|
|
|
} else {
|
|
|
|
datalink_NewState(dl, DATALINK_OPENING);
|
1999-10-21 00:19:33 +00:00
|
|
|
if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
|
|
|
|
bundle_Phase(dl->bundle) == PHASE_TERMINATE)
|
1999-04-06 14:48:10 +00:00
|
|
|
bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
|
1999-03-04 17:42:15 +00:00
|
|
|
if (dl->dial.tries < 0) {
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = dl->cfg.dial.max;
|
|
|
|
dl->dial.incs = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->reconnect_tries--;
|
2000-04-07 23:46:14 +00:00
|
|
|
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);
|
1998-05-21 21:49:08 +00:00
|
|
|
} else {
|
|
|
|
if (dl->phone.next == NULL)
|
1999-03-04 17:42:15 +00:00
|
|
|
datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
|
1998-05-21 21:49:08 +00:00
|
|
|
else
|
|
|
|
datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
|
2000-04-07 23:46:14 +00:00
|
|
|
bundle_Notify(dl->bundle, EX_REDIAL);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-06 20:04:08 +00:00
|
|
|
const char *
|
1998-05-21 21:49:08 +00:00
|
|
|
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';
|
1999-06-18 13:49:01 +00:00
|
|
|
if (*dl->phone.list == '\0')
|
|
|
|
return "";
|
1998-05-21 21:49:08 +00:00
|
|
|
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)
|
2000-04-07 23:46:14 +00:00
|
|
|
log_Printf(LogCHAT, "Phone: %s\n", phone);
|
1998-05-21 21:49:08 +00:00
|
|
|
return phone;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
datalink_LoginDone(struct datalink *dl)
|
|
|
|
{
|
1999-12-03 06:33:10 +00:00
|
|
|
chat_Finish(&dl->chat);
|
1999-10-25 13:49:44 +00:00
|
|
|
|
2002-06-15 08:03:30 +00:00
|
|
|
if (!dl->script.packetmode) {
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = -1;
|
|
|
|
dl->dial.incs = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_NewState(dl, DATALINK_READY);
|
1999-05-08 11:07:56 +00:00
|
|
|
} else if (!physical_Raw(dl->physical)) {
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n");
|
2002-06-15 08:03:30 +00:00
|
|
|
if (dl->script.run) {
|
1999-10-25 13:49:44 +00:00
|
|
|
datalink_NewState(dl, DATALINK_LOGOUT);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL))
|
|
|
|
log_Printf(LogWARN, "Invalid logout script\n");
|
1998-05-21 21:49:08 +00:00
|
|
|
} else {
|
1999-05-12 09:49:12 +00:00
|
|
|
physical_StopDeviceTimer(dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
if (dl->physical->type == PHYS_DEDICATED)
|
|
|
|
/* force a redial timeout */
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Close(dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_HangupDone(dl);
|
|
|
|
}
|
|
|
|
} else {
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = -1;
|
|
|
|
dl->dial.incs = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp);
|
2002-03-04 10:08:57 +00:00
|
|
|
async_Setup(&dl->physical->async);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
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
|
2000-03-14 01:46:09 +00:00
|
|
|
datalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
|
1998-05-21 21:49:08 +00:00
|
|
|
int *n)
|
|
|
|
{
|
|
|
|
struct datalink *dl = descriptor2datalink(d);
|
|
|
|
int result;
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
switch (dl->state) {
|
|
|
|
case DATALINK_CLOSED:
|
1999-11-28 15:50:08 +00:00
|
|
|
if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|
|
|
|
|
PHYS_FOREGROUND|PHYS_DDIAL)) &&
|
1999-06-10 09:06:30 +00:00
|
|
|
!dl->bundle->CleaningUp)
|
1998-05-21 21:49:08 +00:00
|
|
|
/*
|
1998-05-29 18:32:11 +00:00
|
|
|
* Our first time in - DEDICATED & DDIAL never come down, and
|
1999-11-28 15:50:08 +00:00
|
|
|
* DIRECT, FOREGROUND & BACKGROUND get deleted when they enter
|
|
|
|
* DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up()
|
|
|
|
* and fall through.
|
1998-05-21 21:49:08 +00:00
|
|
|
*/
|
|
|
|
datalink_Up(dl, 1, 1);
|
|
|
|
else
|
|
|
|
break;
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
case DATALINK_OPENING:
|
1999-03-04 17:42:15 +00:00
|
|
|
if (dl->dial.timer.state != TIMER_RUNNING) {
|
|
|
|
if (--dl->dial.tries < 0)
|
|
|
|
dl->dial.tries = 0;
|
2004-09-05 01:46:52 +00:00
|
|
|
if (physical_Open(dl->physical) >= 0) {
|
1998-08-09 15:34:11 +00:00
|
|
|
log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n"
|
|
|
|
"Type `~?' for help\r\n", dl->name,
|
|
|
|
dl->physical->name.full);
|
1998-05-21 21:49:08 +00:00
|
|
|
if (dl->script.run) {
|
|
|
|
datalink_NewState(dl, DATALINK_DIAL);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.dial,
|
|
|
|
*dl->cfg.script.dial ?
|
|
|
|
datalink_ChoosePhoneNumber(dl) : ""))
|
|
|
|
log_Printf(LogWARN, "Invalid dial script\n");
|
1998-05-29 18:32:11 +00:00
|
|
|
if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->cfg.dial.max)
|
|
|
|
log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n",
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->name, dl->cfg.dial.max - dl->dial.tries,
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->cfg.dial.max);
|
|
|
|
} else
|
1999-10-07 07:32:12 +00:00
|
|
|
datalink_NewState(dl, DATALINK_CARRIER);
|
1998-12-15 19:12:24 +00:00
|
|
|
return datalink_UpdateSet(d, r, w, e, n);
|
1998-05-21 21:49:08 +00:00
|
|
|
} else {
|
1998-05-29 18:32:11 +00:00
|
|
|
if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->cfg.dial.max)
|
1999-05-08 11:07:56 +00:00
|
|
|
log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n",
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max);
|
1998-05-21 21:49:08 +00:00
|
|
|
else
|
1999-05-08 11:07:56 +00:00
|
|
|
log_Printf(LogCHAT, "Failed to open device\n");
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
if (dl->bundle->CleaningUp ||
|
1998-05-29 18:32:11 +00:00
|
|
|
(!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->cfg.dial.max && dl->dial.tries == 0)) {
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_NewState(dl, DATALINK_CLOSED);
|
|
|
|
dl->reconnect_tries = 0;
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = -1;
|
1998-08-09 15:34:11 +00:00
|
|
|
log_WritePrompts(dl, "Failed to open %s\n",
|
|
|
|
dl->physical->name.full);
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_LinkClosed(dl->bundle, dl);
|
|
|
|
}
|
1998-08-09 15:34:11 +00:00
|
|
|
if (!dl->bundle->CleaningUp) {
|
1999-03-04 17:42:15 +00:00
|
|
|
int timeout;
|
|
|
|
|
|
|
|
timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
|
2000-04-07 23:46:14 +00:00
|
|
|
bundle_Notify(dl->bundle, EX_REDIAL);
|
1998-08-09 15:34:11 +00:00
|
|
|
log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n",
|
1999-02-25 12:00:04 +00:00
|
|
|
dl->physical->name.full, timeout);
|
1998-08-09 15:34:11 +00:00
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
1999-08-06 20:04:08 +00:00
|
|
|
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:
|
1999-10-07 07:32:12 +00:00
|
|
|
if (dl->script.run) {
|
|
|
|
datalink_NewState(dl, DATALINK_LOGIN);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL))
|
|
|
|
log_Printf(LogWARN, "Invalid login script\n");
|
1999-10-07 07:32:12 +00:00
|
|
|
} else
|
|
|
|
datalink_LoginDone(dl);
|
1999-08-06 20:04:08 +00:00
|
|
|
return datalink_UpdateSet(d, r, w, e, n);
|
|
|
|
|
|
|
|
case CARRIER_LOST:
|
|
|
|
physical_Offline(dl->physical); /* Is this required ? */
|
2002-06-15 08:03:30 +00:00
|
|
|
if (dl->script.run) {
|
1999-10-07 07:32:12 +00:00
|
|
|
datalink_NewState(dl, DATALINK_HANGUP);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
|
|
|
|
log_Printf(LogWARN, "Invalid hangup script\n");
|
1999-11-09 23:21:47 +00:00
|
|
|
return datalink_UpdateSet(d, r, w, e, n);
|
|
|
|
} else {
|
1999-10-07 07:32:12 +00:00
|
|
|
datalink_HangupDone(dl);
|
1999-11-09 23:21:47 +00:00
|
|
|
return 0; /* Maybe bundle_CleanDatalinks() has something to do */
|
|
|
|
}
|
1999-08-06 20:04:08 +00:00
|
|
|
}
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_HANGUP:
|
|
|
|
case DATALINK_DIAL:
|
1999-10-25 13:49:44 +00:00
|
|
|
case DATALINK_LOGOUT:
|
1998-05-21 21:49:08 +00:00
|
|
|
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:
|
1999-08-06 20:04:08 +00:00
|
|
|
datalink_NewState(dl, DATALINK_CARRIER);
|
1998-05-21 21:49:08 +00:00
|
|
|
return datalink_UpdateSet(d, r, w, e, n);
|
1999-10-25 13:49:44 +00:00
|
|
|
case DATALINK_LOGOUT:
|
|
|
|
datalink_NewState(dl, DATALINK_HANGUP);
|
|
|
|
physical_Offline(dl->physical);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
|
|
|
|
log_Printf(LogWARN, "Invalid hangup script\n");
|
1999-10-25 13:49:44 +00:00
|
|
|
return datalink_UpdateSet(d, r, w, e, n);
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_LOGIN:
|
1999-01-08 09:04:58 +00:00
|
|
|
dl->phone.alt = NULL;
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_LoginDone(dl);
|
1999-01-20 18:06:52 +00:00
|
|
|
return datalink_UpdateSet(d, r, w, e, n);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
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:
|
1999-10-25 13:49:44 +00:00
|
|
|
case DATALINK_LOGOUT:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_LOGIN:
|
|
|
|
datalink_NewState(dl, DATALINK_HANGUP);
|
1999-10-25 13:49:44 +00:00
|
|
|
physical_Offline(dl->physical);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
|
|
|
|
log_Printf(LogWARN, "Invalid hangup script\n");
|
1998-05-21 21:49:08 +00:00
|
|
|
return datalink_UpdateSet(d, r, w, e, n);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATALINK_READY:
|
|
|
|
case DATALINK_LCP:
|
|
|
|
case DATALINK_AUTH:
|
1998-08-07 18:42:51 +00:00
|
|
|
case DATALINK_CBCP:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_OPEN:
|
1999-02-11 10:14:08 +00:00
|
|
|
result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) +
|
|
|
|
descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
|
1998-05-21 21:49:08 +00:00
|
|
|
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
|
2000-03-14 01:46:09 +00:00
|
|
|
datalink_IsSet(struct fdescriptor *d, const fd_set *fdset)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct datalink *dl = descriptor2datalink(d);
|
|
|
|
|
|
|
|
switch (dl->state) {
|
|
|
|
case DATALINK_CLOSED:
|
|
|
|
case DATALINK_OPENING:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATALINK_HANGUP:
|
|
|
|
case DATALINK_DIAL:
|
1999-10-25 13:49:44 +00:00
|
|
|
case DATALINK_LOGOUT:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_LOGIN:
|
|
|
|
return descriptor_IsSet(&dl->chat.desc, fdset);
|
|
|
|
|
|
|
|
case DATALINK_READY:
|
|
|
|
case DATALINK_LCP:
|
|
|
|
case DATALINK_AUTH:
|
1998-08-07 18:42:51 +00:00
|
|
|
case DATALINK_CBCP:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_OPEN:
|
1999-02-11 10:14:08 +00:00
|
|
|
return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 :
|
|
|
|
descriptor_IsSet(&dl->physical->desc, fdset);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-03-14 01:46:09 +00:00
|
|
|
datalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct datalink *dl = descriptor2datalink(d);
|
|
|
|
|
|
|
|
switch (dl->state) {
|
|
|
|
case DATALINK_CLOSED:
|
|
|
|
case DATALINK_OPENING:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATALINK_HANGUP:
|
|
|
|
case DATALINK_DIAL:
|
1999-10-25 13:49:44 +00:00
|
|
|
case DATALINK_LOGOUT:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_LOGIN:
|
|
|
|
descriptor_Read(&dl->chat.desc, bundle, fdset);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATALINK_READY:
|
|
|
|
case DATALINK_LCP:
|
|
|
|
case DATALINK_AUTH:
|
1998-08-07 18:42:51 +00:00
|
|
|
case DATALINK_CBCP:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_OPEN:
|
1999-02-11 10:14:08 +00:00
|
|
|
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);
|
1998-05-21 21:49:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-06-24 19:33:36 +00:00
|
|
|
static int
|
2000-10-30 00:15:29 +00:00
|
|
|
datalink_Write(struct fdescriptor *d, struct bundle *bundle,
|
|
|
|
const fd_set *fdset)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct datalink *dl = descriptor2datalink(d);
|
1998-06-24 19:33:36 +00:00
|
|
|
int result = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
switch (dl->state) {
|
|
|
|
case DATALINK_CLOSED:
|
|
|
|
case DATALINK_OPENING:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATALINK_HANGUP:
|
|
|
|
case DATALINK_DIAL:
|
1999-10-25 13:49:44 +00:00
|
|
|
case DATALINK_LOGOUT:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_LOGIN:
|
2002-03-30 12:30:09 +00:00
|
|
|
if ((result = descriptor_Write(&dl->chat.desc, bundle, fdset)) == -1) {
|
|
|
|
datalink_ComeDown(dl, CLOSE_NORMAL);
|
|
|
|
result = 0;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DATALINK_READY:
|
|
|
|
case DATALINK_LCP:
|
|
|
|
case DATALINK_AUTH:
|
1998-08-07 18:42:51 +00:00
|
|
|
case DATALINK_CBCP:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_OPEN:
|
1999-02-11 10:14:08 +00:00
|
|
|
if (descriptor_IsSet(&dl->chap.desc, fdset))
|
2002-03-30 12:30:09 +00:00
|
|
|
switch (descriptor_Write(&dl->chap.desc, bundle, fdset)) {
|
|
|
|
case -1:
|
|
|
|
datalink_ComeDown(dl, CLOSE_NORMAL);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
result++;
|
|
|
|
}
|
1999-02-11 10:14:08 +00:00
|
|
|
if (descriptor_IsSet(&dl->physical->desc, fdset))
|
2002-03-30 12:30:09 +00:00
|
|
|
switch (descriptor_Write(&dl->physical->desc, bundle, fdset)) {
|
|
|
|
case -1:
|
|
|
|
datalink_ComeDown(dl, CLOSE_NORMAL);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
result++;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
break;
|
|
|
|
}
|
1998-06-24 19:33:36 +00:00
|
|
|
|
|
|
|
return result;
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
2002-03-30 12:30:09 +00:00
|
|
|
void
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_ComeDown(struct datalink *dl, int how)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
2001-02-04 01:08:22 +00:00
|
|
|
int stayonline;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
2001-02-04 01:08:22 +00:00
|
|
|
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) {
|
1999-05-12 09:49:12 +00:00
|
|
|
physical_StopDeviceTimer(dl->physical);
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_NewState(dl, DATALINK_READY);
|
|
|
|
} else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Offline(dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
if (dl->script.run && dl->state != DATALINK_OPENING) {
|
1999-10-25 13:49:44 +00:00
|
|
|
if (dl->state == DATALINK_LOGOUT) {
|
|
|
|
datalink_NewState(dl, DATALINK_HANGUP);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
|
|
|
|
log_Printf(LogWARN, "Invalid hangup script\n");
|
1999-10-25 13:49:44 +00:00
|
|
|
} else {
|
|
|
|
datalink_NewState(dl, DATALINK_LOGOUT);
|
1999-12-20 20:30:02 +00:00
|
|
|
if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL))
|
|
|
|
log_Printf(LogWARN, "Invalid logout script\n");
|
1999-10-25 13:49:44 +00:00
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
} 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;
|
1999-02-18 00:52:15 +00:00
|
|
|
struct lcp *lcp = &dl->physical->link.lcp;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
if (fp->proto == PROTO_LCP) {
|
1999-02-06 02:54:47 +00:00
|
|
|
datalink_GotAuthname(dl, "");
|
1999-02-18 00:52:15 +00:00
|
|
|
lcp->auth_ineed = lcp->want_auth;
|
|
|
|
lcp->auth_iwait = lcp->his_auth;
|
|
|
|
if (lcp->his_auth || lcp->want_auth) {
|
1999-04-05 21:52:10 +00:00
|
|
|
if (bundle_Phase(dl->bundle) != PHASE_NETWORK)
|
1998-05-21 21:49:08 +00:00
|
|
|
bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
|
|
|
|
log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
|
1999-02-18 00:52:15 +00:00
|
|
|
Auth2Nam(lcp->his_auth, lcp->his_authtype),
|
|
|
|
Auth2Nam(lcp->want_auth, lcp->want_authtype));
|
|
|
|
if (lcp->his_auth == PROTO_PAP)
|
1999-02-06 02:54:47 +00:00
|
|
|
auth_StartReq(&dl->pap);
|
1999-02-18 00:52:15 +00:00
|
|
|
if (lcp->want_auth == PROTO_CHAP)
|
1999-02-06 02:54:47 +00:00
|
|
|
auth_StartReq(&dl->chap.auth);
|
1998-05-21 21:49:08 +00:00
|
|
|
} else
|
|
|
|
datalink_AuthOk(dl);
|
2001-07-03 22:20:19 +00:00
|
|
|
} else if (fp->proto == PROTO_CCP)
|
|
|
|
(*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.ccp.fsm);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 02:11:28 +00:00
|
|
|
static void
|
|
|
|
datalink_AuthReInit(struct datalink *dl)
|
|
|
|
{
|
|
|
|
auth_StopTimer(&dl->pap);
|
|
|
|
auth_StopTimer(&dl->chap.auth);
|
|
|
|
chap_ReInit(&dl->chap);
|
|
|
|
}
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
void
|
1999-02-06 02:54:47 +00:00
|
|
|
datalink_GotAuthname(struct datalink *dl, const char *name)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
1999-02-06 02:54:47 +00:00
|
|
|
strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1);
|
|
|
|
dl->peer.authname[sizeof dl->peer.authname - 1] = '\0';
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-08-07 18:42:51 +00:00
|
|
|
datalink_NCPUp(struct datalink *dl)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
1998-06-30 23:04:17 +00:00
|
|
|
int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp);
|
1998-05-23 13:38:09 +00:00
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
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 */
|
1998-08-07 18:42:51 +00:00
|
|
|
auth_Select(dl->bundle, dl->peer.authname);
|
1999-08-05 10:32:16 +00:00
|
|
|
bundle_CalculateBandwidth(dl->bundle);
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH */
|
1998-05-21 21:49:08 +00:00
|
|
|
case MP_ADDED:
|
|
|
|
/* We're in multilink mode ! */
|
1998-05-23 13:38:09 +00:00
|
|
|
dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */
|
1999-08-05 10:32:16 +00:00
|
|
|
bundle_CalculateBandwidth(dl->bundle);
|
1998-05-21 21:49:08 +00:00
|
|
|
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);
|
1998-06-25 22:33:31 +00:00
|
|
|
datalink_NewState(dl, DATALINK_OPEN);
|
1999-08-05 10:32:16 +00:00
|
|
|
bundle_CalculateBandwidth(dl->bundle);
|
1998-06-25 22:33:31 +00:00
|
|
|
(*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
|
1998-05-21 21:49:08 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
dl->bundle->ncp.mp.peer = dl->peer;
|
2001-08-14 16:05:52 +00:00
|
|
|
ncp_SetLink(&dl->bundle->ncp, &dl->physical->link);
|
1998-08-07 18:42:51 +00:00
|
|
|
auth_Select(dl->bundle, dl->peer.authname);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
1998-06-30 23:04:17 +00:00
|
|
|
if (ccpok) {
|
|
|
|
fsm_Up(&dl->physical->link.ccp.fsm);
|
|
|
|
fsm_Open(&dl->physical->link.ccp.fsm);
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_NewState(dl, DATALINK_OPEN);
|
|
|
|
bundle_NewPhase(dl->bundle, PHASE_NETWORK);
|
|
|
|
(*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
|
|
|
|
}
|
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
void
|
|
|
|
datalink_CBCPComplete(struct datalink *dl)
|
|
|
|
{
|
|
|
|
datalink_NewState(dl, DATALINK_LCP);
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
1998-08-07 18:42:51 +00:00
|
|
|
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)
|
|
|
|
{
|
1999-01-12 21:50:20 +00:00
|
|
|
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 */
|
1998-08-07 18:42:51 +00:00
|
|
|
datalink_NewState(dl, DATALINK_CBCP);
|
|
|
|
cbcp_Up(&dl->cbcp);
|
|
|
|
} else if (dl->physical->link.lcp.want_callback.opmask) {
|
1999-01-12 21:50:20 +00:00
|
|
|
/* It's not CBCP */
|
1998-08-07 18:42:51 +00:00
|
|
|
log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name);
|
|
|
|
datalink_NewState(dl, DATALINK_LCP);
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
1998-08-07 18:42:51 +00:00
|
|
|
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);
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
1998-08-07 18:42:51 +00:00
|
|
|
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);
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
1998-08-07 18:42:51 +00:00
|
|
|
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);
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
1998-08-07 18:42:51 +00:00
|
|
|
fsm_Close(&dl->physical->link.lcp.fsm);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
void
|
|
|
|
datalink_AuthNotOk(struct datalink *dl)
|
|
|
|
{
|
|
|
|
datalink_NewState(dl, DATALINK_LCP);
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
1998-05-21 21:49:08 +00:00
|
|
|
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);
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(&dl->physical->link.ccp.fsm);
|
1998-06-12 17:45:10 +00:00
|
|
|
datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */
|
1998-05-21 21:49:08 +00:00
|
|
|
(*dl->parent->LayerDown)(dl->parent->object, fp);
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH (just in case) */
|
1998-08-07 18:42:51 +00:00
|
|
|
|
|
|
|
case DATALINK_CBCP:
|
|
|
|
if (!dl->cbcp.required)
|
|
|
|
cbcp_Down(&dl->cbcp);
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH (just in case) */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
case DATALINK_AUTH:
|
|
|
|
timer_Stop(&dl->pap.authtimer);
|
|
|
|
timer_Stop(&dl->chap.auth.authtimer);
|
|
|
|
}
|
|
|
|
datalink_NewState(dl, DATALINK_LCP);
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(fp);
|
1998-05-21 21:49:08 +00:00
|
|
|
(*dl->parent->LayerFinish)(dl->parent->object, fp);
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_ComeDown(dl, CLOSE_NORMAL);
|
1998-05-21 21:49:08 +00:00
|
|
|
} 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';
|
1999-10-25 13:49:44 +00:00
|
|
|
*dl->cfg.script.logout = '\0';
|
1998-05-21 21:49:08 +00:00
|
|
|
*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";
|
1998-06-15 19:05:27 +00:00
|
|
|
dl->stayonline = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->script.run = 1;
|
|
|
|
dl->script.packetmode = 1;
|
|
|
|
mp_linkInit(&dl->mp);
|
|
|
|
|
|
|
|
dl->bundle = bundle;
|
|
|
|
dl->next = NULL;
|
|
|
|
|
1999-03-04 17:42:15 +00:00
|
|
|
memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->cfg.dial.max = 1;
|
|
|
|
dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
|
|
|
|
dl->cfg.dial.timeout = DIAL_TIMEOUT;
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->cfg.dial.inc = 0;
|
|
|
|
dl->cfg.dial.maxinc = 10;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
dl->reconnect_tries = 0;
|
|
|
|
dl->cfg.reconnect.max = 0;
|
|
|
|
dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
|
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
dl->cfg.callback.opmask = 0;
|
|
|
|
dl->cfg.cbcp.delay = 0;
|
|
|
|
*dl->cfg.cbcp.phone = '\0';
|
|
|
|
dl->cfg.cbcp.fsmretry = DEF_FSMRETRY;
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
if ((dl->physical = physical_Create(dl, type)) == NULL) {
|
1998-05-21 21:49:08 +00:00
|
|
|
free(dl->name);
|
|
|
|
free(dl);
|
|
|
|
return NULL;
|
|
|
|
}
|
1999-02-06 02:54:47 +00:00
|
|
|
|
|
|
|
pap_Init(&dl->pap, dl->physical);
|
|
|
|
chap_Init(&dl->chap, dl->physical);
|
1998-08-07 18:42:51 +00:00
|
|
|
cbcp_Init(&dl->cbcp, dl->physical);
|
1999-10-25 13:49:44 +00:00
|
|
|
|
|
|
|
memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */
|
1999-12-03 06:33:10 +00:00
|
|
|
chat_Init(&dl->chat, dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
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;
|
1999-03-04 17:42:15 +00:00
|
|
|
memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
|
|
|
|
dl->dial.tries = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
|
|
|
|
1999-05-08 11:07:56 +00:00
|
|
|
if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) {
|
1998-05-21 21:49:08 +00:00
|
|
|
free(dl->name);
|
|
|
|
free(dl);
|
|
|
|
return NULL;
|
|
|
|
}
|
1999-02-06 02:54:47 +00:00
|
|
|
pap_Init(&dl->pap, dl->physical);
|
Allow control over the number of ConfigREQ & TermREQ attempts
that are made in each of the FSMs (LCP, CCP & IPCP) and the
number of REQs/Challenges for PAP/CHAP by accepting more arguments
in the ``set {c,ip,l}cpretry'' and ``set {ch,p}apretry'' commands.
Change the non-convergence thresholds to 3 times the number of configured
REQ tries (rather than the previous fixed ``10''). We now notice
repeated NAKs and REJs rather than just REQs.
Don't suggest that CHAP 0x05 isn't supported when it's not configured.
Fix some bugs that expose themselves with smaller numbers of retries:
o Handle instantaneous disconnects (set device /dev/null) correctly
by stopping all fsm timers in fsm2initial.
o Don't forget to uu_unlock() devices that are files but are not
ttys (set device /dev/zero).
Fix a *HORRENDOUS* bug in RFC1661 (already fixed for an Open event in state
``Closed''):
According to the state transition table, a RCR+ or RCR- received in
the ``Stopped'' state are supposed to InitRestartCounter, SendConfigReq
and SendConfig{Ack,Nak}. However, in ``Stopped'', we haven't yet
done a TLS (or the last thing we did is a TLF). We must therefore
do the TLS at this point !
This was never noticed before because LCP and CCP used not use
LayerStart() for anything interesting, and IPCP tends to go into
Stopped then get a Down because of an LCP RTR rather than getting a
RCR again.
1999-02-26 21:28:14 +00:00
|
|
|
dl->pap.cfg = odl->pap.cfg;
|
1999-02-06 02:54:47 +00:00
|
|
|
|
|
|
|
chap_Init(&dl->chap, dl->physical);
|
Allow control over the number of ConfigREQ & TermREQ attempts
that are made in each of the FSMs (LCP, CCP & IPCP) and the
number of REQs/Challenges for PAP/CHAP by accepting more arguments
in the ``set {c,ip,l}cpretry'' and ``set {ch,p}apretry'' commands.
Change the non-convergence thresholds to 3 times the number of configured
REQ tries (rather than the previous fixed ``10''). We now notice
repeated NAKs and REJs rather than just REQs.
Don't suggest that CHAP 0x05 isn't supported when it's not configured.
Fix some bugs that expose themselves with smaller numbers of retries:
o Handle instantaneous disconnects (set device /dev/null) correctly
by stopping all fsm timers in fsm2initial.
o Don't forget to uu_unlock() devices that are files but are not
ttys (set device /dev/zero).
Fix a *HORRENDOUS* bug in RFC1661 (already fixed for an Open event in state
``Closed''):
According to the state transition table, a RCR+ or RCR- received in
the ``Stopped'' state are supposed to InitRestartCounter, SendConfigReq
and SendConfig{Ack,Nak}. However, in ``Stopped'', we haven't yet
done a TLS (or the last thing we did is a TLF). We must therefore
do the TLS at this point !
This was never noticed before because LCP and CCP used not use
LayerStart() for anything interesting, and IPCP tends to go into
Stopped then get a Down because of an LCP RTR rather than getting a
RCR again.
1999-02-26 21:28:14 +00:00
|
|
|
dl->chap.auth.cfg = odl->chap.auth.cfg;
|
1999-02-06 02:54:47 +00:00
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
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);
|
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
cbcp_Init(&dl->cbcp, dl->physical);
|
1999-10-25 13:49:44 +00:00
|
|
|
|
|
|
|
memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */
|
1999-12-03 06:33:10 +00:00
|
|
|
chat_Init(&dl->chat, dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
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:
|
1999-12-03 06:33:10 +00:00
|
|
|
chat_Finish(&dl->chat); /* Gotta blat the timers ! */
|
1998-05-21 21:49:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-12-03 06:33:10 +00:00
|
|
|
chat_Destroy(&dl->chat);
|
1999-03-04 17:42:15 +00:00
|
|
|
timer_Stop(&dl->dial.timer);
|
1998-05-21 21:49:08 +00:00
|
|
|
result = dl->next;
|
1999-05-08 11:07:56 +00:00
|
|
|
physical_Destroy(dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
free(dl->name);
|
|
|
|
free(dl);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
datalink_Up(struct datalink *dl, int runscripts, int packetmode)
|
|
|
|
{
|
2003-03-26 02:03:08 +00:00
|
|
|
if (!Enabled(dl->bundle, OPT_FORCE_SCRIPTS) &&
|
|
|
|
(dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)))
|
1998-05-21 21:49:08 +00:00
|
|
|
/* 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;
|
1999-03-04 17:42:15 +00:00
|
|
|
dl->dial.tries = dl->cfg.dial.max;
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->script.run = runscripts;
|
|
|
|
dl->script.packetmode = packetmode;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATALINK_OPENING:
|
|
|
|
if (!dl->script.run && runscripts)
|
|
|
|
dl->script.run = 1;
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
case DATALINK_DIAL:
|
|
|
|
case DATALINK_LOGIN:
|
|
|
|
case DATALINK_READY:
|
|
|
|
if (!dl->script.packetmode && packetmode) {
|
|
|
|
dl->script.packetmode = 1;
|
2000-05-26 08:26:56 +00:00
|
|
|
if (dl->state == DATALINK_READY) {
|
|
|
|
dl->script.run = 0;
|
|
|
|
datalink_NewState(dl, DATALINK_CARRIER);
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_Close(struct datalink *dl, int how)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
/* Please close */
|
|
|
|
switch (dl->state) {
|
|
|
|
case DATALINK_OPEN:
|
|
|
|
peerid_Init(&dl->peer);
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(&dl->physical->link.ccp.fsm);
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
case DATALINK_CBCP:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_AUTH:
|
|
|
|
case DATALINK_LCP:
|
1999-02-17 02:11:28 +00:00
|
|
|
datalink_AuthReInit(dl);
|
2001-02-04 01:08:22 +00:00
|
|
|
if (how == CLOSE_LCP)
|
|
|
|
datalink_DontHangup(dl);
|
|
|
|
else if (how == CLOSE_STAYDOWN)
|
|
|
|
datalink_StayDown(dl);
|
1998-05-21 21:49:08 +00:00
|
|
|
fsm_Close(&dl->physical->link.lcp.fsm);
|
1999-10-08 16:09:15 +00:00
|
|
|
break;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
default:
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_ComeDown(dl, how);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_Down(struct datalink *dl, int how)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
/* Carrier is lost */
|
|
|
|
switch (dl->state) {
|
|
|
|
case DATALINK_OPEN:
|
|
|
|
peerid_Init(&dl->peer);
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(&dl->physical->link.ccp.fsm);
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
case DATALINK_CBCP:
|
1998-05-21 21:49:08 +00:00
|
|
|
case DATALINK_AUTH:
|
|
|
|
case DATALINK_LCP:
|
1998-06-20 00:19:42 +00:00
|
|
|
fsm2initial(&dl->physical->link.lcp.fsm);
|
2000-01-27 00:40:25 +00:00
|
|
|
if (dl->state == DATALINK_OPENING)
|
|
|
|
return; /* we're doing a callback... */
|
2002-08-25 13:30:43 +00:00
|
|
|
/* FALLTHROUGH */
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
default:
|
1998-06-15 19:05:27 +00:00
|
|
|
datalink_ComeDown(dl, how);
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
datalink_StayDown(struct datalink *dl)
|
|
|
|
{
|
2001-02-04 01:08:22 +00:00
|
|
|
dl->dial.tries = -1;
|
1998-05-21 21:49:08 +00:00
|
|
|
dl->reconnect_tries = 0;
|
2001-02-04 01:08:22 +00:00
|
|
|
dl->stayonline = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
}
|
|
|
|
|
1998-06-15 19:05:27 +00:00
|
|
|
void
|
|
|
|
datalink_DontHangup(struct datalink *dl)
|
|
|
|
{
|
2001-02-04 01:08:22 +00:00
|
|
|
dl->dial.tries = -1;
|
|
|
|
dl->reconnect_tries = 0;
|
|
|
|
dl->stayonline = dl->state >= DATALINK_LCP ? 1 : 0;
|
1998-06-15 19:05:27 +00:00
|
|
|
}
|
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
int
|
|
|
|
datalink_Show(struct cmdargs const *arg)
|
|
|
|
{
|
|
|
|
prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " State: %s\n",
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_State(arg->cx));
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Peer name: ");
|
1998-05-21 21:49:08 +00:00
|
|
|
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");
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Discriminator: %s\n",
|
1998-05-21 21:49:08 +00:00
|
|
|
mp_Enddisc(arg->cx->peer.enddisc.class,
|
|
|
|
arg->cx->peer.enddisc.address,
|
|
|
|
arg->cx->peer.enddisc.len));
|
|
|
|
|
|
|
|
prompt_Printf(arg->prompt, "\nDefaults:\n");
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Phone List: %s\n",
|
1998-05-21 21:49:08 +00:00
|
|
|
arg->cx->cfg.phone.list);
|
|
|
|
if (arg->cx->cfg.dial.max)
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Dial tries: %d, delay ",
|
1998-05-21 21:49:08 +00:00
|
|
|
arg->cx->cfg.dial.max);
|
|
|
|
else
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Dial tries: infinite, delay ");
|
1999-02-25 12:00:04 +00:00
|
|
|
if (arg->cx->cfg.dial.next_timeout >= 0)
|
1998-05-21 21:49:08 +00:00
|
|
|
prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout);
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, "random/");
|
1999-02-25 12:00:04 +00:00
|
|
|
if (arg->cx->cfg.dial.timeout >= 0)
|
1998-05-21 21:49:08 +00:00
|
|
|
prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout);
|
|
|
|
else
|
|
|
|
prompt_Printf(arg->prompt, "random\n");
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ",
|
1998-05-21 21:49:08 +00:00
|
|
|
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");
|
1998-08-07 18:42:51 +00:00
|
|
|
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);
|
1998-10-17 12:28:06 +00:00
|
|
|
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);
|
1998-08-07 18:42:51 +00:00
|
|
|
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",
|
1998-05-21 21:49:08 +00:00
|
|
|
arg->cx->cfg.script.dial);
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Login Script: %s\n",
|
1998-05-21 21:49:08 +00:00
|
|
|
arg->cx->cfg.script.login);
|
1999-10-25 13:49:44 +00:00
|
|
|
prompt_Printf(arg->prompt, " Logout Script: %s\n",
|
|
|
|
arg->cx->cfg.script.logout);
|
1998-08-07 18:42:51 +00:00
|
|
|
prompt_Printf(arg->prompt, " Hangup Script: %s\n",
|
1998-05-21 21:49:08 +00:00
|
|
|
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)
|
|
|
|
{
|
1999-03-04 17:42:15 +00:00
|
|
|
const char *sep, *osep;
|
|
|
|
int timeout, inc, maxinc, tries;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-03-04 17:42:15 +00:00
|
|
|
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) {
|
1998-05-21 21:49:08 +00:00
|
|
|
arg->cx->cfg.dial.next_timeout = -1;
|
|
|
|
randinit();
|
|
|
|
} else {
|
1999-03-04 17:42:15 +00:00
|
|
|
timeout = atoi(sep);
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
|
|
|
}
|
1999-03-04 17:42:15 +00:00
|
|
|
|
1998-05-21 21:49:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
1999-12-27 11:54:57 +00:00
|
|
|
static const char * const states[] = {
|
1998-05-21 21:49:08 +00:00
|
|
|
"closed",
|
|
|
|
"opening",
|
|
|
|
"hangup",
|
|
|
|
"dial",
|
1999-08-06 20:04:08 +00:00
|
|
|
"carrier",
|
1999-10-25 13:49:44 +00:00
|
|
|
"logout",
|
1998-05-21 21:49:08 +00:00
|
|
|
"login",
|
|
|
|
"ready",
|
|
|
|
"lcp",
|
|
|
|
"auth",
|
1998-08-07 18:42:51 +00:00
|
|
|
"cbcp",
|
1998-05-21 21:49:08 +00:00
|
|
|
"open"
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *
|
|
|
|
datalink_State(struct datalink *dl)
|
|
|
|
{
|
2004-09-05 01:46:52 +00:00
|
|
|
if (dl->state >= sizeof states / sizeof states[0])
|
1998-05-21 21:49:08 +00:00
|
|
|
return "unknown";
|
|
|
|
return states[dl->state];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-09-05 01:46:52 +00:00
|
|
|
datalink_NewState(struct datalink *dl, unsigned state)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
if (state != dl->state) {
|
2004-09-05 01:46:52 +00:00
|
|
|
if (state < sizeof states / sizeof states[0]) {
|
1998-05-21 21:49:08 +00:00
|
|
|
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,
|
1999-11-06 22:50:59 +00:00
|
|
|
int fd, int *auxfd, int *nauxfd)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
struct datalink *dl, *cdl;
|
Allow control over the number of ConfigREQ & TermREQ attempts
that are made in each of the FSMs (LCP, CCP & IPCP) and the
number of REQs/Challenges for PAP/CHAP by accepting more arguments
in the ``set {c,ip,l}cpretry'' and ``set {ch,p}apretry'' commands.
Change the non-convergence thresholds to 3 times the number of configured
REQ tries (rather than the previous fixed ``10''). We now notice
repeated NAKs and REJs rather than just REQs.
Don't suggest that CHAP 0x05 isn't supported when it's not configured.
Fix some bugs that expose themselves with smaller numbers of retries:
o Handle instantaneous disconnects (set device /dev/null) correctly
by stopping all fsm timers in fsm2initial.
o Don't forget to uu_unlock() devices that are files but are not
ttys (set device /dev/zero).
Fix a *HORRENDOUS* bug in RFC1661 (already fixed for an Open event in state
``Closed''):
According to the state transition table, a RCR+ or RCR- received in
the ``Stopped'' state are supposed to InitRestartCounter, SendConfigReq
and SendConfig{Ack,Nak}. However, in ``Stopped'', we haven't yet
done a TLS (or the last thing we did is a TLF). We must therefore
do the TLS at this point !
This was never noticed before because LCP and CCP used not use
LayerStart() for anything interesting, and IPCP tends to go into
Stopped then get a Down because of an LCP RTR rather than getting a
RCR again.
1999-02-26 21:28:14 +00:00
|
|
|
struct fsm_retry copy;
|
2004-10-11 09:45:58 +00:00
|
|
|
char *oname, *pname;
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
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)) {
|
2004-10-11 09:45:58 +00:00
|
|
|
if ((pname = datalink_NextName(dl)) == NULL) {
|
|
|
|
for ((*niov)--; *niov < maxiov; (*niov)++)
|
|
|
|
free(iov[*niov].iov_base);
|
|
|
|
return NULL;
|
|
|
|
} else if (oname)
|
|
|
|
free(pname);
|
1998-05-21 21:49:08 +00:00
|
|
|
else
|
2004-10-11 09:45:58 +00:00
|
|
|
oname = pname;
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
1999-03-04 17:42:15 +00:00
|
|
|
memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
|
|
|
|
dl->dial.tries = 0;
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
if (!dl->physical) {
|
|
|
|
free(dl->name);
|
|
|
|
free(dl);
|
|
|
|
dl = NULL;
|
|
|
|
} else {
|
Allow control over the number of ConfigREQ & TermREQ attempts
that are made in each of the FSMs (LCP, CCP & IPCP) and the
number of REQs/Challenges for PAP/CHAP by accepting more arguments
in the ``set {c,ip,l}cpretry'' and ``set {ch,p}apretry'' commands.
Change the non-convergence thresholds to 3 times the number of configured
REQ tries (rather than the previous fixed ``10''). We now notice
repeated NAKs and REJs rather than just REQs.
Don't suggest that CHAP 0x05 isn't supported when it's not configured.
Fix some bugs that expose themselves with smaller numbers of retries:
o Handle instantaneous disconnects (set device /dev/null) correctly
by stopping all fsm timers in fsm2initial.
o Don't forget to uu_unlock() devices that are files but are not
ttys (set device /dev/zero).
Fix a *HORRENDOUS* bug in RFC1661 (already fixed for an Open event in state
``Closed''):
According to the state transition table, a RCR+ or RCR- received in
the ``Stopped'' state are supposed to InitRestartCounter, SendConfigReq
and SendConfig{Ack,Nak}. However, in ``Stopped'', we haven't yet
done a TLS (or the last thing we did is a TLF). We must therefore
do the TLS at this point !
This was never noticed before because LCP and CCP used not use
LayerStart() for anything interesting, and IPCP tends to go into
Stopped then get a Down because of an LCP RTR rather than getting a
RCR again.
1999-02-26 21:28:14 +00:00
|
|
|
copy = dl->pap.cfg.fsm;
|
1999-02-06 02:54:47 +00:00
|
|
|
pap_Init(&dl->pap, dl->physical);
|
Allow control over the number of ConfigREQ & TermREQ attempts
that are made in each of the FSMs (LCP, CCP & IPCP) and the
number of REQs/Challenges for PAP/CHAP by accepting more arguments
in the ``set {c,ip,l}cpretry'' and ``set {ch,p}apretry'' commands.
Change the non-convergence thresholds to 3 times the number of configured
REQ tries (rather than the previous fixed ``10''). We now notice
repeated NAKs and REJs rather than just REQs.
Don't suggest that CHAP 0x05 isn't supported when it's not configured.
Fix some bugs that expose themselves with smaller numbers of retries:
o Handle instantaneous disconnects (set device /dev/null) correctly
by stopping all fsm timers in fsm2initial.
o Don't forget to uu_unlock() devices that are files but are not
ttys (set device /dev/zero).
Fix a *HORRENDOUS* bug in RFC1661 (already fixed for an Open event in state
``Closed''):
According to the state transition table, a RCR+ or RCR- received in
the ``Stopped'' state are supposed to InitRestartCounter, SendConfigReq
and SendConfig{Ack,Nak}. However, in ``Stopped'', we haven't yet
done a TLS (or the last thing we did is a TLF). We must therefore
do the TLS at this point !
This was never noticed before because LCP and CCP used not use
LayerStart() for anything interesting, and IPCP tends to go into
Stopped then get a Down because of an LCP RTR rather than getting a
RCR again.
1999-02-26 21:28:14 +00:00
|
|
|
dl->pap.cfg.fsm = copy;
|
1999-02-06 02:54:47 +00:00
|
|
|
|
Allow control over the number of ConfigREQ & TermREQ attempts
that are made in each of the FSMs (LCP, CCP & IPCP) and the
number of REQs/Challenges for PAP/CHAP by accepting more arguments
in the ``set {c,ip,l}cpretry'' and ``set {ch,p}apretry'' commands.
Change the non-convergence thresholds to 3 times the number of configured
REQ tries (rather than the previous fixed ``10''). We now notice
repeated NAKs and REJs rather than just REQs.
Don't suggest that CHAP 0x05 isn't supported when it's not configured.
Fix some bugs that expose themselves with smaller numbers of retries:
o Handle instantaneous disconnects (set device /dev/null) correctly
by stopping all fsm timers in fsm2initial.
o Don't forget to uu_unlock() devices that are files but are not
ttys (set device /dev/zero).
Fix a *HORRENDOUS* bug in RFC1661 (already fixed for an Open event in state
``Closed''):
According to the state transition table, a RCR+ or RCR- received in
the ``Stopped'' state are supposed to InitRestartCounter, SendConfigReq
and SendConfig{Ack,Nak}. However, in ``Stopped'', we haven't yet
done a TLS (or the last thing we did is a TLF). We must therefore
do the TLS at this point !
This was never noticed before because LCP and CCP used not use
LayerStart() for anything interesting, and IPCP tends to go into
Stopped then get a Down because of an LCP RTR rather than getting a
RCR again.
1999-02-26 21:28:14 +00:00
|
|
|
copy = dl->chap.auth.cfg.fsm;
|
1999-02-06 02:54:47 +00:00
|
|
|
chap_Init(&dl->chap, dl->physical);
|
Allow control over the number of ConfigREQ & TermREQ attempts
that are made in each of the FSMs (LCP, CCP & IPCP) and the
number of REQs/Challenges for PAP/CHAP by accepting more arguments
in the ``set {c,ip,l}cpretry'' and ``set {ch,p}apretry'' commands.
Change the non-convergence thresholds to 3 times the number of configured
REQ tries (rather than the previous fixed ``10''). We now notice
repeated NAKs and REJs rather than just REQs.
Don't suggest that CHAP 0x05 isn't supported when it's not configured.
Fix some bugs that expose themselves with smaller numbers of retries:
o Handle instantaneous disconnects (set device /dev/null) correctly
by stopping all fsm timers in fsm2initial.
o Don't forget to uu_unlock() devices that are files but are not
ttys (set device /dev/zero).
Fix a *HORRENDOUS* bug in RFC1661 (already fixed for an Open event in state
``Closed''):
According to the state transition table, a RCR+ or RCR- received in
the ``Stopped'' state are supposed to InitRestartCounter, SendConfigReq
and SendConfig{Ack,Nak}. However, in ``Stopped'', we haven't yet
done a TLS (or the last thing we did is a TLF). We must therefore
do the TLS at this point !
This was never noticed before because LCP and CCP used not use
LayerStart() for anything interesting, and IPCP tends to go into
Stopped then get a Down because of an LCP RTR rather than getting a
RCR again.
1999-02-26 21:28:14 +00:00
|
|
|
dl->chap.auth.cfg.fsm = copy;
|
1999-02-06 02:54:47 +00:00
|
|
|
|
1998-08-07 18:42:51 +00:00
|
|
|
cbcp_Init(&dl->cbcp, dl->physical);
|
1999-10-25 13:49:44 +00:00
|
|
|
|
|
|
|
memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */
|
1999-12-03 06:33:10 +00:00
|
|
|
chat_Init(&dl->chat, dl->physical);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
log_Printf(LogPHASE, "%s: Transferred in %s state\n",
|
|
|
|
dl->name, datalink_State(dl));
|
|
|
|
}
|
|
|
|
|
|
|
|
return dl;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1998-05-28 23:15:40 +00:00
|
|
|
datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
int *auxfd, int *nauxfd)
|
1998-05-21 21:49:08 +00:00
|
|
|
{
|
|
|
|
/* If `dl' is NULL, we're allocating before a Fromiov() */
|
|
|
|
int link_fd;
|
|
|
|
|
|
|
|
if (dl) {
|
1999-03-04 17:42:15 +00:00
|
|
|
timer_Stop(&dl->dial.timer);
|
1998-08-07 18:42:51 +00:00
|
|
|
/* The following is purely for the sake of paranoia */
|
|
|
|
cbcp_Down(&dl->cbcp);
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
iov[*niov].iov_base = (void *)dl;
|
1998-05-21 21:49:08 +00:00
|
|
|
iov[(*niov)++].iov_len = sizeof *dl;
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL;
|
1998-05-21 21:49:08 +00:00
|
|
|
iov[(*niov)++].iov_len = DATALINK_MAXNAME;
|
|
|
|
|
1999-11-06 22:50:59 +00:00
|
|
|
link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd,
|
Rewrite the link descriptor transfer code in MP mode.
Previously, ppp attempted to bind() to a local domain tcp socket
based on the peer authname & enddisc. If it succeeded, it listen()ed
and became MP server. If it failed, it connect()ed and became MP
client. The server then select()ed on the descriptor, accept()ed
it and wrote its pid to it then read the link data & link file descriptor,
and finally sent an ack (``!''). The client would read() the server
pid, transfer the link lock to that pid, send the link data & descriptor
and read the ack. It would then close the descriptor and clean up.
There was a race between the bind() and listen() where someone could
attempt to connect() and fail.
This change removes the race. Now ppp makes the RCVBUF big enough on a
socket descriptor and attempts to bind() to a local domain *udp* socket
(same name as before). If it succeeds, it becomes MP server. If it
fails, it sets the SNDBUF and connect()s, becoming MP client. The server
select()s on the descriptor and recvmsg()s the message, insisting on at
least two descriptors (plus the link data). It uses the second descriptor
to write() its pid then read()s an ack (``!''). The client creates a
socketpair() and sendmsg()s the link data, link descriptor and one of
the socketpair descriptors. It then read()s the server pid from the
other socketpair descriptor, transfers any locks and write()s an ack.
Now, there can be no race, and a connect() failure indicates a stale
socket file.
This also fixes MP ppp over ethernet, where the struct msghdr was being
misconstructed when transferring the control socket descriptor.
Also, if we fail to send the link, don't hang around in a ``session
owner'' state, just do the setsid() and fork() if it's required to
disown a tty.
UDP idea suggested by: Chris Bennet from Mindspring at FreeBSDCon
1999-11-25 02:47:04 +00:00
|
|
|
nauxfd);
|
1998-05-21 21:49:08 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2004-10-11 09:45:58 +00:00
|
|
|
static char *
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_NextName(struct datalink *dl)
|
|
|
|
{
|
|
|
|
int f, n;
|
|
|
|
char *name, *oname;
|
|
|
|
|
|
|
|
n = strlen(dl->name);
|
2004-10-11 09:45:58 +00:00
|
|
|
if ((name = (char *)malloc(n+3)) == NULL) {
|
|
|
|
log_Printf(LogERROR, "datalink_NextName: Out of memory !\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
1998-05-25 02:22:38 +00:00
|
|
|
dl->name = name;
|
|
|
|
/* our physical link name isn't updated (it probably isn't created yet) */
|
1998-05-21 21:49:08 +00:00
|
|
|
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;
|
1999-11-28 15:50:08 +00:00
|
|
|
if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) &&
|
|
|
|
dl->state <= DATALINK_READY)
|
1998-05-21 21:49:08 +00:00
|
|
|
datalink_Up(dl, 1, 1);
|
|
|
|
return 1;
|
|
|
|
}
|
1999-03-04 17:42:15 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|