13006ec67SBrian Somers /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
43006ec67SBrian Somers * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
53006ec67SBrian Somers * All rights reserved.
63006ec67SBrian Somers *
73006ec67SBrian Somers * Redistribution and use in source and binary forms, with or without
83006ec67SBrian Somers * modification, are permitted provided that the following conditions
93006ec67SBrian Somers * are met:
103006ec67SBrian Somers * 1. Redistributions of source code must retain the above copyright
113006ec67SBrian Somers * notice, this list of conditions and the following disclaimer.
123006ec67SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
133006ec67SBrian Somers * notice, this list of conditions and the following disclaimer in the
143006ec67SBrian Somers * documentation and/or other materials provided with the distribution.
153006ec67SBrian Somers *
163006ec67SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173006ec67SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183006ec67SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193006ec67SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203006ec67SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213006ec67SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223006ec67SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233006ec67SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243006ec67SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253006ec67SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263006ec67SBrian Somers * SUCH DAMAGE.
273006ec67SBrian Somers */
283006ec67SBrian Somers
29972a1bcfSBrian Somers #include <sys/param.h>
303006ec67SBrian Somers #include <netinet/in.h>
31eaa4df37SBrian Somers #include <netinet/in_systm.h>
32eaa4df37SBrian Somers #include <netinet/ip.h>
3330949fd4SBrian Somers #include <sys/socket.h>
341fa665f5SBrian Somers #include <sys/un.h>
353006ec67SBrian Somers
366f384573SBrian Somers #include <ctype.h>
376eafd353SBrian Somers #include <stdarg.h>
38c7cc5030SBrian Somers #include <stdio.h>
393006ec67SBrian Somers #include <stdlib.h>
403006ec67SBrian Somers #include <string.h>
4196c9bb21SBrian Somers #include <sys/uio.h>
423006ec67SBrian Somers #include <termios.h>
433006ec67SBrian Somers
445d9e6103SBrian Somers #include "layer.h"
453006ec67SBrian Somers #include "mbuf.h"
463006ec67SBrian Somers #include "log.h"
473006ec67SBrian Somers #include "defs.h"
483006ec67SBrian Somers #include "timer.h"
493006ec67SBrian Somers #include "fsm.h"
503006ec67SBrian Somers #include "descriptor.h"
51879ed6faSBrian Somers #include "lqr.h"
523006ec67SBrian Somers #include "hdlc.h"
531038894eSBrian Somers #include "lcp.h"
543006ec67SBrian Somers #include "async.h"
553006ec67SBrian Somers #include "throughput.h"
563b0f8d2eSBrian Somers #include "ccp.h"
573006ec67SBrian Somers #include "link.h"
583006ec67SBrian Somers #include "physical.h"
595828db6dSBrian Somers #include "iplist.h"
60eaa4df37SBrian Somers #include "slcompress.h"
6130949fd4SBrian Somers #include "ncpaddr.h"
625828db6dSBrian Somers #include "ipcp.h"
635ca5389aSBrian Somers #include "filter.h"
643b0f8d2eSBrian Somers #include "mp.h"
65972a1bcfSBrian Somers #ifndef NORADIUS
66972a1bcfSBrian Somers #include "radius.h"
67972a1bcfSBrian Somers #endif
6830949fd4SBrian Somers #include "ipv6cp.h"
6930949fd4SBrian Somers #include "ncp.h"
703006ec67SBrian Somers #include "bundle.h"
713006ec67SBrian Somers #include "chat.h"
72e2ebb036SBrian Somers #include "auth.h"
73c7cc5030SBrian Somers #include "prompt.h"
745d9e6103SBrian Somers #include "proto.h"
75e2ebb036SBrian Somers #include "pap.h"
76e2ebb036SBrian Somers #include "chap.h"
77565e35e5SBrian Somers #include "command.h"
7892b09558SBrian Somers #include "cbcp.h"
79e2ebb036SBrian Somers #include "datalink.h"
80c7cc5030SBrian Somers
81030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *);
82057f1760SBrian Somers static void datalink_NewState(struct datalink *, unsigned);
835d604c11SBrian Somers static char *datalink_NextName(struct datalink *);
843006ec67SBrian Somers
853006ec67SBrian Somers static void
datalink_OpenTimeout(void * v)863006ec67SBrian Somers datalink_OpenTimeout(void *v)
873006ec67SBrian Somers {
883006ec67SBrian Somers struct datalink *dl = (struct datalink *)v;
893006ec67SBrian Somers
90c11e57a3SBrian Somers timer_Stop(&dl->dial.timer);
913006ec67SBrian Somers if (dl->state == DATALINK_OPENING)
92b42135deSBrian Somers log_Printf(LogCHAT, "%s: Redial timer expired.\n", dl->name);
933006ec67SBrian Somers }
943006ec67SBrian Somers
95b5c347a3SBrian Somers static int
datalink_StartDialTimer(struct datalink * dl,int Timeout)963006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout)
973006ec67SBrian Somers {
98b5c347a3SBrian Somers int result = Timeout;
993006ec67SBrian Somers
100c11e57a3SBrian Somers timer_Stop(&dl->dial.timer);
101a65be227SBrian Somers if (Timeout < 0)
102b5c347a3SBrian Somers result = (random() % DIAL_TIMEOUT) + 1;
103dad51e5cSBrian Somers dl->dial.timer.load = result ? result * SECTICKS : 1;
104c11e57a3SBrian Somers dl->dial.timer.func = datalink_OpenTimeout;
105c11e57a3SBrian Somers dl->dial.timer.name = "dial";
106c11e57a3SBrian Somers dl->dial.timer.arg = dl;
107c11e57a3SBrian Somers timer_Start(&dl->dial.timer);
1083006ec67SBrian Somers if (dl->state == DATALINK_OPENING)
109dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
110a65be227SBrian Somers dl->name, result);
111b5c347a3SBrian Somers return result;
1123006ec67SBrian Somers }
1133006ec67SBrian Somers
1143006ec67SBrian Somers static void
datalink_HangupDone(struct datalink * dl)1153006ec67SBrian Somers datalink_HangupDone(struct datalink *dl)
1163006ec67SBrian Somers {
117030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp &&
1185d9e6103SBrian Somers dl->physical->fd != -1) {
1195d9e6103SBrian Somers /* Don't close our device if the link is dedicated */
120030e4ebbSBrian Somers datalink_LoginDone(dl);
121030e4ebbSBrian Somers return;
122030e4ebbSBrian Somers }
123030e4ebbSBrian Somers
124ffcfaec7SBrian Somers chat_Finish(&dl->chat);
1255d9e6103SBrian Somers physical_Close(dl->physical);
126565e35e5SBrian Somers dl->phone.chosen = "N/A";
1273006ec67SBrian Somers
12892b09558SBrian Somers if (dl->cbcp.required) {
12992b09558SBrian Somers log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone);
13092b09558SBrian Somers dl->cfg.callback.opmask = 0;
13192b09558SBrian Somers strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone,
13292b09558SBrian Somers sizeof dl->cfg.phone.list - 1);
13392b09558SBrian Somers dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0';
13492b09558SBrian Somers dl->phone.alt = dl->phone.next = NULL;
13592b09558SBrian Somers dl->reconnect_tries = dl->cfg.reconnect.max;
136c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max;
137c11e57a3SBrian Somers dl->dial.incs = 0;
13892b09558SBrian Somers dl->script.run = 1;
13992b09558SBrian Somers dl->script.packetmode = 1;
14092b09558SBrian Somers if (!physical_SetMode(dl->physical, PHYS_BACKGROUND))
14192b09558SBrian Somers log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n");
14292b09558SBrian Somers bundle_LinksRemoved(dl->bundle);
143c11e57a3SBrian Somers /* if dial.timeout is < 0 (random), we don't override fsm.delay */
14492b09558SBrian Somers if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout)
14592b09558SBrian Somers dl->cbcp.fsm.delay = dl->cfg.dial.timeout;
14692b09558SBrian Somers datalink_StartDialTimer(dl, dl->cbcp.fsm.delay);
14792b09558SBrian Somers cbcp_Down(&dl->cbcp);
14892b09558SBrian Somers datalink_NewState(dl, DATALINK_OPENING);
1491b02dfb4SBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
1501b02dfb4SBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE)
1510ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
15292b09558SBrian Somers } else if (dl->bundle->CleaningUp ||
1536f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) ||
154c11e57a3SBrian Somers ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) &&
15581358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) {
1569ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED);
157c11e57a3SBrian Somers dl->dial.tries = -1;
158c11e57a3SBrian Somers dl->dial.incs = 0;
1593006ec67SBrian Somers dl->reconnect_tries = 0;
1603006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl);
1614b567bf2SBrian Somers if (!dl->bundle->CleaningUp &&
1624b567bf2SBrian Somers !(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)))
163c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
1643006ec67SBrian Somers } else {
1659ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING);
1661b02dfb4SBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
1671b02dfb4SBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE)
1680ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
169c11e57a3SBrian Somers if (dl->dial.tries < 0) {
170565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
171c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max;
172c11e57a3SBrian Somers dl->dial.incs = 0;
173abff9baeSBrian Somers dl->reconnect_tries--;
174b42135deSBrian Somers log_Printf(LogCHAT, "%s: Reconnect try %d of %d\n",
175b42135deSBrian Somers dl->name, dl->cfg.reconnect.max - dl->reconnect_tries,
176b42135deSBrian Somers dl->cfg.reconnect.max);
177b42135deSBrian Somers bundle_Notify(dl->bundle, EX_RECONNECT);
178abff9baeSBrian Somers } else {
179f9545805SBrian Somers if (dl->phone.next == NULL)
180c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
1813006ec67SBrian Somers else
182565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
183b42135deSBrian Somers bundle_Notify(dl->bundle, EX_REDIAL);
1843006ec67SBrian Somers }
185abff9baeSBrian Somers }
186abff9baeSBrian Somers }
1873006ec67SBrian Somers
188eb6e5e05SBrian Somers const char *
datalink_ChoosePhoneNumber(struct datalink * dl)189f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl)
190f9545805SBrian Somers {
191f9545805SBrian Somers char *phone;
192f9545805SBrian Somers
193f9545805SBrian Somers if (dl->phone.alt == NULL) {
194f9545805SBrian Somers if (dl->phone.next == NULL) {
195f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
196f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0';
19708da4867SBrian Somers if (*dl->phone.list == '\0')
19808da4867SBrian Somers return "";
199f9545805SBrian Somers dl->phone.next = dl->phone.list;
200f9545805SBrian Somers }
201f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":");
202f9545805SBrian Somers }
203f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|");
204f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]";
205f9545805SBrian Somers if (*phone)
206b42135deSBrian Somers log_Printf(LogCHAT, "Phone: %s\n", phone);
207f9545805SBrian Somers return phone;
208f9545805SBrian Somers }
209f9545805SBrian Somers
210c5a5a6caSBrian Somers static void
datalink_LoginDone(struct datalink * dl)211c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl)
212c5a5a6caSBrian Somers {
213ffcfaec7SBrian Somers chat_Finish(&dl->chat);
214c116e0c0SBrian Somers
215d345321bSBrian Somers if (!dl->script.packetmode) {
216c11e57a3SBrian Somers dl->dial.tries = -1;
217c11e57a3SBrian Somers dl->dial.incs = 0;
2189ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY);
2195d9e6103SBrian Somers } else if (!physical_Raw(dl->physical)) {
220c11e57a3SBrian Somers dl->dial.tries = 0;
221dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n");
222c5a5a6caSBrian Somers if (dl->script.run) {
223c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_LOGOUT);
224c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL))
225c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid logout script\n");
226030e4ebbSBrian Somers } else {
2276815097bSBrian Somers physical_StopDeviceTimer(dl->physical);
228030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED)
229030e4ebbSBrian Somers /* force a redial timeout */
2305d9e6103SBrian Somers physical_Close(dl->physical);
231c5a5a6caSBrian Somers datalink_HangupDone(dl);
232030e4ebbSBrian Somers }
233c5a5a6caSBrian Somers } else {
234c11e57a3SBrian Somers dl->dial.tries = -1;
235c11e57a3SBrian Somers dl->dial.incs = 0;
236c7cc5030SBrian Somers
237643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp);
238ea59de37SBrian Somers async_Setup(&dl->physical->async);
2393b0f8d2eSBrian Somers
240cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
241cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode);
2423b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp);
243503a7782SBrian Somers
2449ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP);
245dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm);
246dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm);
247c5a5a6caSBrian Somers }
248c5a5a6caSBrian Somers }
249c5a5a6caSBrian Somers
2503006ec67SBrian Somers static int
datalink_UpdateSet(struct fdescriptor * d,fd_set * r,fd_set * w,fd_set * e,int * n)251f013f33eSBrian Somers datalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
2523006ec67SBrian Somers int *n)
2533006ec67SBrian Somers {
2543006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d);
2553006ec67SBrian Somers int result;
2563006ec67SBrian Somers
257310c3babSBrian Somers result = 0;
2583006ec67SBrian Somers switch (dl->state) {
2593006ec67SBrian Somers case DATALINK_CLOSED:
260f6a4e748SBrian Somers if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|
261f6a4e748SBrian Somers PHYS_FOREGROUND|PHYS_DDIAL)) &&
262194c225dSBrian Somers !dl->bundle->CleaningUp)
263565e35e5SBrian Somers /*
26481358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and
265f6a4e748SBrian Somers * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter
266f6a4e748SBrian Somers * DATALINK_CLOSED. Go to DATALINK_OPENING via datalink_Up()
267f6a4e748SBrian Somers * and fall through.
268565e35e5SBrian Somers */
269565e35e5SBrian Somers datalink_Up(dl, 1, 1);
270565e35e5SBrian Somers else
271310c3babSBrian Somers break;
272f0067240SPhilippe Charnier /* FALLTHROUGH */
2733006ec67SBrian Somers
2743006ec67SBrian Somers case DATALINK_OPENING:
275c11e57a3SBrian Somers if (dl->dial.timer.state != TIMER_RUNNING) {
276c11e57a3SBrian Somers if (--dl->dial.tries < 0)
277c11e57a3SBrian Somers dl->dial.tries = 0;
278057f1760SBrian Somers if (physical_Open(dl->physical) >= 0) {
279bf1d3ff6SBrian Somers log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n"
280bf1d3ff6SBrian Somers "Type `~?' for help\r\n", dl->name,
281bf1d3ff6SBrian Somers dl->physical->name.full);
282c5a5a6caSBrian Somers if (dl->script.run) {
2839ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL);
284c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.dial,
285c39aa54eSBrian Somers *dl->cfg.script.dial ?
286c39aa54eSBrian Somers datalink_ChoosePhoneNumber(dl) : ""))
287c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid dial script\n");
28881358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
289565e35e5SBrian Somers dl->cfg.dial.max)
290dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n",
291c11e57a3SBrian Somers dl->name, dl->cfg.dial.max - dl->dial.tries,
292565e35e5SBrian Somers dl->cfg.dial.max);
293c5a5a6caSBrian Somers } else
29414e34a55SBrian Somers datalink_NewState(dl, DATALINK_CARRIER);
2958b09cf1cSBrian Somers return datalink_UpdateSet(d, r, w, e, n);
2963006ec67SBrian Somers } else {
29781358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
298565e35e5SBrian Somers dl->cfg.dial.max)
2995d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n",
300c11e57a3SBrian Somers dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max);
3013006ec67SBrian Somers else
3025d9e6103SBrian Somers log_Printf(LogCHAT, "Failed to open device\n");
3033006ec67SBrian Somers
3043b0f8d2eSBrian Somers if (dl->bundle->CleaningUp ||
30581358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
306c11e57a3SBrian Somers dl->cfg.dial.max && dl->dial.tries == 0)) {
3079ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED);
3083006ec67SBrian Somers dl->reconnect_tries = 0;
309c11e57a3SBrian Somers dl->dial.tries = -1;
310bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s\n",
311bf1d3ff6SBrian Somers dl->physical->name.full);
3125b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl);
313c5a5a6caSBrian Somers }
314bf1d3ff6SBrian Somers if (!dl->bundle->CleaningUp) {
315c11e57a3SBrian Somers int timeout;
316c11e57a3SBrian Somers
317c11e57a3SBrian Somers timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
318b42135deSBrian Somers bundle_Notify(dl->bundle, EX_REDIAL);
319bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n",
320b5c347a3SBrian Somers dl->physical->name.full, timeout);
3213006ec67SBrian Somers }
3223006ec67SBrian Somers }
323bf1d3ff6SBrian Somers }
324310c3babSBrian Somers break;
3253006ec67SBrian Somers
326eb6e5e05SBrian Somers case DATALINK_CARRIER:
327eb6e5e05SBrian Somers /* Wait for carrier on the device */
328eb6e5e05SBrian Somers switch (physical_AwaitCarrier(dl->physical)) {
329eb6e5e05SBrian Somers case CARRIER_PENDING:
330eb6e5e05SBrian Somers log_Printf(LogDEBUG, "Waiting for carrier\n");
331eb6e5e05SBrian Somers return 0; /* A device timer is running to wake us up again */
332eb6e5e05SBrian Somers
333eb6e5e05SBrian Somers case CARRIER_OK:
33414e34a55SBrian Somers if (dl->script.run) {
335eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_LOGIN);
336c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL))
337c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid login script\n");
33814e34a55SBrian Somers } else
33914e34a55SBrian Somers datalink_LoginDone(dl);
340eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n);
341eb6e5e05SBrian Somers
342eb6e5e05SBrian Somers case CARRIER_LOST:
343eb6e5e05SBrian Somers physical_Offline(dl->physical); /* Is this required ? */
34414e34a55SBrian Somers if (dl->script.run) {
34514e34a55SBrian Somers datalink_NewState(dl, DATALINK_HANGUP);
346c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
347c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n");
348eb6e5e05SBrian Somers return datalink_UpdateSet(d, r, w, e, n);
349da8b7034SBrian Somers } else {
350da8b7034SBrian Somers datalink_HangupDone(dl);
351da8b7034SBrian Somers return 0; /* Maybe bundle_CleanDatalinks() has something to do */
352da8b7034SBrian Somers }
353eb6e5e05SBrian Somers }
354eb6e5e05SBrian Somers
3553006ec67SBrian Somers case DATALINK_HANGUP:
3563006ec67SBrian Somers case DATALINK_DIAL:
357c116e0c0SBrian Somers case DATALINK_LOGOUT:
3583006ec67SBrian Somers case DATALINK_LOGIN:
3593006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
3603006ec67SBrian Somers switch (dl->chat.state) {
3613006ec67SBrian Somers case CHAT_DONE:
3623006ec67SBrian Somers /* script succeeded */
3633006ec67SBrian Somers switch(dl->state) {
3643006ec67SBrian Somers case DATALINK_HANGUP:
3653006ec67SBrian Somers datalink_HangupDone(dl);
3663006ec67SBrian Somers break;
3673006ec67SBrian Somers case DATALINK_DIAL:
368eb6e5e05SBrian Somers datalink_NewState(dl, DATALINK_CARRIER);
3691342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n);
370c116e0c0SBrian Somers case DATALINK_LOGOUT:
371c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_HANGUP);
372c116e0c0SBrian Somers physical_Offline(dl->physical);
373c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
374c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n");
375c116e0c0SBrian Somers return datalink_UpdateSet(d, r, w, e, n);
3763006ec67SBrian Somers case DATALINK_LOGIN:
37747dd77c1SBrian Somers dl->phone.alt = NULL;
378c5a5a6caSBrian Somers datalink_LoginDone(dl);
379b51a60ccSBrian Somers return datalink_UpdateSet(d, r, w, e, n);
3803006ec67SBrian Somers }
3813006ec67SBrian Somers break;
3823006ec67SBrian Somers case CHAT_FAILED:
3833006ec67SBrian Somers /* Going down - script failed */
384dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n");
3853006ec67SBrian Somers switch(dl->state) {
3863006ec67SBrian Somers case DATALINK_HANGUP:
3873006ec67SBrian Somers datalink_HangupDone(dl);
3883006ec67SBrian Somers break;
3893006ec67SBrian Somers case DATALINK_DIAL:
390c116e0c0SBrian Somers case DATALINK_LOGOUT:
3913006ec67SBrian Somers case DATALINK_LOGIN:
3929ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP);
393c116e0c0SBrian Somers physical_Offline(dl->physical);
394c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
395c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n");
3961342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n);
3973006ec67SBrian Somers }
3983006ec67SBrian Somers break;
3993006ec67SBrian Somers }
4003006ec67SBrian Somers break;
401c7cc5030SBrian Somers
402c7cc5030SBrian Somers case DATALINK_READY:
403e2ebb036SBrian Somers case DATALINK_LCP:
404e2ebb036SBrian Somers case DATALINK_AUTH:
40592b09558SBrian Somers case DATALINK_CBCP:
4063006ec67SBrian Somers case DATALINK_OPEN:
40758330d7bSBrian Somers result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) +
40858330d7bSBrian Somers descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
4093006ec67SBrian Somers break;
4103006ec67SBrian Somers }
4113006ec67SBrian Somers return result;
4123006ec67SBrian Somers }
4133006ec67SBrian Somers
414ea722969SBrian Somers int
datalink_RemoveFromSet(struct datalink * dl,fd_set * r,fd_set * w,fd_set * e)415ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e)
416ea722969SBrian Somers {
417ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e);
418ea722969SBrian Somers }
419ea722969SBrian Somers
4203006ec67SBrian Somers static int
datalink_IsSet(struct fdescriptor * d,const fd_set * fdset)421f013f33eSBrian Somers datalink_IsSet(struct fdescriptor *d, const fd_set *fdset)
4223006ec67SBrian Somers {
4233006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d);
4243006ec67SBrian Somers
4253006ec67SBrian Somers switch (dl->state) {
4263006ec67SBrian Somers case DATALINK_CLOSED:
427c7cc5030SBrian Somers case DATALINK_OPENING:
4283006ec67SBrian Somers break;
429c7cc5030SBrian Somers
4303006ec67SBrian Somers case DATALINK_HANGUP:
4313006ec67SBrian Somers case DATALINK_DIAL:
432c116e0c0SBrian Somers case DATALINK_LOGOUT:
4333006ec67SBrian Somers case DATALINK_LOGIN:
4343006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset);
435c7cc5030SBrian Somers
436c7cc5030SBrian Somers case DATALINK_READY:
437e2ebb036SBrian Somers case DATALINK_LCP:
438e2ebb036SBrian Somers case DATALINK_AUTH:
43992b09558SBrian Somers case DATALINK_CBCP:
4403006ec67SBrian Somers case DATALINK_OPEN:
44158330d7bSBrian Somers return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 :
44258330d7bSBrian Somers descriptor_IsSet(&dl->physical->desc, fdset);
4433006ec67SBrian Somers }
4443006ec67SBrian Somers return 0;
4453006ec67SBrian Somers }
4463006ec67SBrian Somers
4473006ec67SBrian Somers static void
datalink_Read(struct fdescriptor * d,struct bundle * bundle,const fd_set * fdset)448f013f33eSBrian Somers datalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
4493006ec67SBrian Somers {
4503006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d);
4513006ec67SBrian Somers
4523006ec67SBrian Somers switch (dl->state) {
4533006ec67SBrian Somers case DATALINK_CLOSED:
454c7cc5030SBrian Somers case DATALINK_OPENING:
4553006ec67SBrian Somers break;
456c7cc5030SBrian Somers
4573006ec67SBrian Somers case DATALINK_HANGUP:
4583006ec67SBrian Somers case DATALINK_DIAL:
459c116e0c0SBrian Somers case DATALINK_LOGOUT:
4603006ec67SBrian Somers case DATALINK_LOGIN:
4613006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset);
4623006ec67SBrian Somers break;
463c7cc5030SBrian Somers
464c7cc5030SBrian Somers case DATALINK_READY:
465e2ebb036SBrian Somers case DATALINK_LCP:
466e2ebb036SBrian Somers case DATALINK_AUTH:
46792b09558SBrian Somers case DATALINK_CBCP:
4683006ec67SBrian Somers case DATALINK_OPEN:
46958330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset))
47058330d7bSBrian Somers descriptor_Read(&dl->chap.desc, bundle, fdset);
47158330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset))
4723006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset);
4733006ec67SBrian Somers break;
4743006ec67SBrian Somers }
4753006ec67SBrian Somers }
4763006ec67SBrian Somers
4771af29a6eSBrian Somers static int
datalink_Write(struct fdescriptor * d,struct bundle * bundle,const fd_set * fdset)4789b996792SBrian Somers datalink_Write(struct fdescriptor *d, struct bundle *bundle,
4799b996792SBrian Somers const fd_set *fdset)
4803006ec67SBrian Somers {
4813006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d);
4821af29a6eSBrian Somers int result = 0;
4833006ec67SBrian Somers
4843006ec67SBrian Somers switch (dl->state) {
4853006ec67SBrian Somers case DATALINK_CLOSED:
486c7cc5030SBrian Somers case DATALINK_OPENING:
4873006ec67SBrian Somers break;
488c7cc5030SBrian Somers
4893006ec67SBrian Somers case DATALINK_HANGUP:
4903006ec67SBrian Somers case DATALINK_DIAL:
491c116e0c0SBrian Somers case DATALINK_LOGOUT:
4923006ec67SBrian Somers case DATALINK_LOGIN:
493fb11a9c2SBrian Somers if ((result = descriptor_Write(&dl->chat.desc, bundle, fdset)) == -1) {
494fb11a9c2SBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL);
495fb11a9c2SBrian Somers result = 0;
496fb11a9c2SBrian Somers }
4973006ec67SBrian Somers break;
498c7cc5030SBrian Somers
499c7cc5030SBrian Somers case DATALINK_READY:
500e2ebb036SBrian Somers case DATALINK_LCP:
501e2ebb036SBrian Somers case DATALINK_AUTH:
50292b09558SBrian Somers case DATALINK_CBCP:
5033006ec67SBrian Somers case DATALINK_OPEN:
50458330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset))
505fb11a9c2SBrian Somers switch (descriptor_Write(&dl->chap.desc, bundle, fdset)) {
506fb11a9c2SBrian Somers case -1:
507fb11a9c2SBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL);
508fb11a9c2SBrian Somers break;
509fb11a9c2SBrian Somers case 1:
510fb11a9c2SBrian Somers result++;
511fb11a9c2SBrian Somers }
51258330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset))
513fb11a9c2SBrian Somers switch (descriptor_Write(&dl->physical->desc, bundle, fdset)) {
514fb11a9c2SBrian Somers case -1:
515fb11a9c2SBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL);
516fb11a9c2SBrian Somers break;
517fb11a9c2SBrian Somers case 1:
518fb11a9c2SBrian Somers result++;
519fb11a9c2SBrian Somers }
5203006ec67SBrian Somers break;
5213006ec67SBrian Somers }
5221af29a6eSBrian Somers
5231af29a6eSBrian Somers return result;
5243006ec67SBrian Somers }
5253006ec67SBrian Somers
526fb11a9c2SBrian Somers void
datalink_ComeDown(struct datalink * dl,int how)5279c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how)
528e2ebb036SBrian Somers {
5292fc2f705SBrian Somers int stayonline;
530e2ebb036SBrian Somers
5312fc2f705SBrian Somers if (how == CLOSE_LCP)
5322fc2f705SBrian Somers datalink_DontHangup(dl);
5332fc2f705SBrian Somers else if (how == CLOSE_STAYDOWN)
5342fc2f705SBrian Somers datalink_StayDown(dl);
5352fc2f705SBrian Somers
5362fc2f705SBrian Somers stayonline = dl->stayonline;
5379c81b87dSBrian Somers dl->stayonline = 0;
5382fc2f705SBrian Somers
5392fc2f705SBrian Somers if (dl->state >= DATALINK_READY && stayonline) {
5406815097bSBrian Somers physical_StopDeviceTimer(dl->physical);
5419c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY);
5429c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
5435d9e6103SBrian Somers physical_Offline(dl->physical);
544e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) {
545c116e0c0SBrian Somers if (dl->state == DATALINK_LOGOUT) {
5469ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP);
547c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
548c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid hangup script\n");
549c116e0c0SBrian Somers } else {
550c116e0c0SBrian Somers datalink_NewState(dl, DATALINK_LOGOUT);
551c39aa54eSBrian Somers if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL))
552c39aa54eSBrian Somers log_Printf(LogWARN, "Invalid logout script\n");
553c116e0c0SBrian Somers }
554e2ebb036SBrian Somers } else
555e2ebb036SBrian Somers datalink_HangupDone(dl);
556e2ebb036SBrian Somers }
557e2ebb036SBrian Somers }
558e2ebb036SBrian Somers
559e2ebb036SBrian Somers static void
datalink_LayerStart(void * v,struct fsm * fp)5606d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp)
5616d666775SBrian Somers {
5626d666775SBrian Somers /* The given FSM is about to start up ! */
5636d666775SBrian Somers struct datalink *dl = (struct datalink *)v;
564a611cad6SBrian Somers
56592e872e7SBrian Somers if (fp->proto == PROTO_LCP)
566e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp);
567e2ebb036SBrian Somers }
5686d666775SBrian Somers
5696d666775SBrian Somers static void
datalink_LayerUp(void * v,struct fsm * fp)5706d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp)
5716d666775SBrian Somers {
5726d666775SBrian Somers /* The given fsm is now up */
5736d666775SBrian Somers struct datalink *dl = (struct datalink *)v;
5745e315498SBrian Somers struct lcp *lcp = &dl->physical->link.lcp;
5756d666775SBrian Somers
57692e872e7SBrian Somers if (fp->proto == PROTO_LCP) {
577f0cdd9c0SBrian Somers datalink_GotAuthname(dl, "");
5785e315498SBrian Somers lcp->auth_ineed = lcp->want_auth;
5795e315498SBrian Somers lcp->auth_iwait = lcp->his_auth;
5805e315498SBrian Somers if (lcp->his_auth || lcp->want_auth) {
5815945a079SBrian Somers if (bundle_Phase(dl->bundle) != PHASE_NETWORK)
5825563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
583dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
5845e315498SBrian Somers Auth2Nam(lcp->his_auth, lcp->his_authtype),
5855e315498SBrian Somers Auth2Nam(lcp->want_auth, lcp->want_authtype));
5865e315498SBrian Somers if (lcp->his_auth == PROTO_PAP)
587f0cdd9c0SBrian Somers auth_StartReq(&dl->pap);
5885e315498SBrian Somers if (lcp->want_auth == PROTO_CHAP)
589f0cdd9c0SBrian Somers auth_StartReq(&dl->chap.auth);
590e2ebb036SBrian Somers } else
591e2ebb036SBrian Somers datalink_AuthOk(dl);
5926301d506SBrian Somers } else if (fp->proto == PROTO_CCP)
5936301d506SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.ccp.fsm);
594e2ebb036SBrian Somers }
595e2ebb036SBrian Somers
59664cfdfc6SBrian Somers static void
datalink_AuthReInit(struct datalink * dl)59764cfdfc6SBrian Somers datalink_AuthReInit(struct datalink *dl)
59864cfdfc6SBrian Somers {
59964cfdfc6SBrian Somers auth_StopTimer(&dl->pap);
60064cfdfc6SBrian Somers auth_StopTimer(&dl->chap.auth);
60164cfdfc6SBrian Somers chap_ReInit(&dl->chap);
60264cfdfc6SBrian Somers }
60364cfdfc6SBrian Somers
604e2ebb036SBrian Somers void
datalink_GotAuthname(struct datalink * dl,const char * name)605f0cdd9c0SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name)
606643f4904SBrian Somers {
607f0cdd9c0SBrian Somers strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1);
608f0cdd9c0SBrian Somers dl->peer.authname[sizeof dl->peer.authname - 1] = '\0';
609643f4904SBrian Somers }
610643f4904SBrian Somers
611643f4904SBrian Somers void
datalink_NCPUp(struct datalink * dl)61292b09558SBrian Somers datalink_NCPUp(struct datalink *dl)
613e2ebb036SBrian Somers {
61406337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp);
6151df0a3b9SBrian Somers
616dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) {
6171fa665f5SBrian Somers /* we've authenticated in multilink mode ! */
6181fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) {
6191fa665f5SBrian Somers case MP_LINKSENT:
620ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */
6211fa665f5SBrian Somers return;
6221fa665f5SBrian Somers case MP_UP:
6230a1b5c9dSBrian Somers /* First link in the bundle */
62492b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname);
625ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle);
626f0067240SPhilippe Charnier /* FALLTHROUGH */
6271fa665f5SBrian Somers case MP_ADDED:
6280a1b5c9dSBrian Somers /* We're in multilink mode ! */
6291df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */
630ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle);
6311fa665f5SBrian Somers break;
6321fa665f5SBrian Somers case MP_FAILED:
63349052c95SBrian Somers datalink_AuthNotOk(dl);
63449052c95SBrian Somers return;
63549052c95SBrian Somers }
63649052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) {
637dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name);
638897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN);
639ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle);
640897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
64149052c95SBrian Somers return;
64250abd4c8SBrian Somers } else {
64350abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer;
64430949fd4SBrian Somers ncp_SetLink(&dl->bundle->ncp, &dl->physical->link);
64592b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname);
64650abd4c8SBrian Somers }
64749052c95SBrian Somers
64806337856SBrian Somers if (ccpok) {
649dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm);
650dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm);
65106337856SBrian Somers }
6529ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN);
6533b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK);
6543b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
6556d666775SBrian Somers }
656e2ebb036SBrian Somers
657e2ebb036SBrian Somers void
datalink_CBCPComplete(struct datalink * dl)65892b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl)
65992b09558SBrian Somers {
66092b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP);
66164cfdfc6SBrian Somers datalink_AuthReInit(dl);
66292b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm);
66392b09558SBrian Somers }
66492b09558SBrian Somers
66592b09558SBrian Somers void
datalink_CBCPFailed(struct datalink * dl)66692b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl)
66792b09558SBrian Somers {
66892b09558SBrian Somers cbcp_Down(&dl->cbcp);
66992b09558SBrian Somers datalink_CBCPComplete(dl);
67092b09558SBrian Somers }
67192b09558SBrian Somers
67292b09558SBrian Somers void
datalink_AuthOk(struct datalink * dl)67392b09558SBrian Somers datalink_AuthOk(struct datalink *dl)
67492b09558SBrian Somers {
6755165af6fSBrian Somers if ((dl->physical->link.lcp.his_callback.opmask &
67692b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) ||
6775165af6fSBrian Somers dl->physical->link.lcp.want_callback.opmask &
6785165af6fSBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) &&
6795165af6fSBrian Somers !(dl->physical->link.lcp.want_callback.opmask &
6805165af6fSBrian Somers CALLBACK_BIT(CALLBACK_AUTH))) {
6815165af6fSBrian Somers /* We must have agreed CBCP if AUTH isn't there any more */
68292b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP);
68392b09558SBrian Somers cbcp_Up(&dl->cbcp);
68492b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) {
6855165af6fSBrian Somers /* It's not CBCP */
68692b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name);
68792b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP);
68864cfdfc6SBrian Somers datalink_AuthReInit(dl);
68992b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm);
69092b09558SBrian Somers } else
69192b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) {
69292b09558SBrian Somers case 0:
69392b09558SBrian Somers datalink_NCPUp(dl);
69492b09558SBrian Somers break;
69592b09558SBrian Somers
69692b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH):
69792b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone,
69892b09558SBrian Somers sizeof dl->cbcp.fsm.phone);
69992b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) {
70092b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name,
70192b09558SBrian Somers dl->peer.authname);
70292b09558SBrian Somers *dl->cbcp.fsm.phone = '\0';
70392b09558SBrian Somers } else {
70492b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ',');
70592b09558SBrian Somers if (ptr)
70692b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */
70792b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
70892b09558SBrian Somers dl->cbcp.fsm.phone);
70992b09558SBrian Somers dl->cbcp.required = 1;
71092b09558SBrian Somers }
71192b09558SBrian Somers dl->cbcp.fsm.delay = 0;
71292b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP);
71364cfdfc6SBrian Somers datalink_AuthReInit(dl);
71492b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm);
71592b09558SBrian Somers break;
71692b09558SBrian Somers
71792b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164):
71892b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg,
71992b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1);
72092b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0';
72192b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
72292b09558SBrian Somers dl->cbcp.fsm.phone);
72392b09558SBrian Somers dl->cbcp.required = 1;
72492b09558SBrian Somers dl->cbcp.fsm.delay = 0;
72592b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP);
72664cfdfc6SBrian Somers datalink_AuthReInit(dl);
72792b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm);
72892b09558SBrian Somers break;
72992b09558SBrian Somers
73092b09558SBrian Somers default:
73192b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n",
73292b09558SBrian Somers dl->name);
73392b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP);
73464cfdfc6SBrian Somers datalink_AuthReInit(dl);
73592b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm);
73692b09558SBrian Somers break;
73792b09558SBrian Somers }
73892b09558SBrian Somers }
73992b09558SBrian Somers
74092b09558SBrian Somers void
datalink_AuthNotOk(struct datalink * dl)741e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl)
742e2ebb036SBrian Somers {
7439ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP);
74464cfdfc6SBrian Somers datalink_AuthReInit(dl);
745dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm);
7466d666775SBrian Somers }
7476d666775SBrian Somers
7486d666775SBrian Somers static void
datalink_LayerDown(void * v,struct fsm * fp)7496d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp)
7506d666775SBrian Somers {
7516d666775SBrian Somers /* The given FSM has been told to come down */
7526d666775SBrian Somers struct datalink *dl = (struct datalink *)v;
753a611cad6SBrian Somers
75492e872e7SBrian Somers if (fp->proto == PROTO_LCP) {
755e2ebb036SBrian Somers switch (dl->state) {
756e2ebb036SBrian Somers case DATALINK_OPEN:
757643f4904SBrian Somers peerid_Init(&dl->peer);
75809206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm);
759ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */
760e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp);
761f0067240SPhilippe Charnier /* FALLTHROUGH (just in case) */
76292b09558SBrian Somers
76392b09558SBrian Somers case DATALINK_CBCP:
76492b09558SBrian Somers if (!dl->cbcp.required)
76592b09558SBrian Somers cbcp_Down(&dl->cbcp);
766f0067240SPhilippe Charnier /* FALLTHROUGH (just in case) */
767e2ebb036SBrian Somers
768e2ebb036SBrian Somers case DATALINK_AUTH:
769dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer);
770dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer);
7716d666775SBrian Somers }
7729ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP);
77364cfdfc6SBrian Somers datalink_AuthReInit(dl);
774e2ebb036SBrian Somers }
7756d666775SBrian Somers }
7766d666775SBrian Somers
7776d666775SBrian Somers static void
datalink_LayerFinish(void * v,struct fsm * fp)7786d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp)
7796d666775SBrian Somers {
7806d666775SBrian Somers /* The given fsm is now down */
7816d666775SBrian Somers struct datalink *dl = (struct datalink *)v;
7826d666775SBrian Somers
78392e872e7SBrian Somers if (fp->proto == PROTO_LCP) {
78409206a6fSBrian Somers fsm2initial(fp);
7856d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp);
7869c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL);
7870a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE)
7880a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */
7896d666775SBrian Somers }
7906d666775SBrian Somers
7913006ec67SBrian Somers struct datalink *
datalink_Create(const char * name,struct bundle * bundle,int type)7926f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type)
7933006ec67SBrian Somers {
7943006ec67SBrian Somers struct datalink *dl;
7953006ec67SBrian Somers
7963006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink));
7973006ec67SBrian Somers if (dl == NULL)
7983006ec67SBrian Somers return dl;
7993006ec67SBrian Somers
8003006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR;
8013006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet;
8023006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet;
8033006ec67SBrian Somers dl->desc.Read = datalink_Read;
8043006ec67SBrian Somers dl->desc.Write = datalink_Write;
8055b8b8060SBrian Somers
806e718d1d7SBrian Somers dl->state = DATALINK_CLOSED;
807e718d1d7SBrian Somers
80873a13b5cSBrian Somers *dl->cfg.script.dial = '\0';
80973a13b5cSBrian Somers *dl->cfg.script.login = '\0';
810c116e0c0SBrian Somers *dl->cfg.script.logout = '\0';
81173a13b5cSBrian Somers *dl->cfg.script.hangup = '\0';
812f9545805SBrian Somers *dl->cfg.phone.list = '\0';
813f9545805SBrian Somers *dl->phone.list = '\0';
814f9545805SBrian Somers dl->phone.next = NULL;
815f9545805SBrian Somers dl->phone.alt = NULL;
816f9545805SBrian Somers dl->phone.chosen = "N/A";
8179c81b87dSBrian Somers dl->stayonline = 0;
818c7cc5030SBrian Somers dl->script.run = 1;
819c7cc5030SBrian Somers dl->script.packetmode = 1;
8203b0f8d2eSBrian Somers mp_linkInit(&dl->mp);
8215b8b8060SBrian Somers
8223006ec67SBrian Somers dl->bundle = bundle;
8233006ec67SBrian Somers dl->next = NULL;
824e718d1d7SBrian Somers
825c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
826e718d1d7SBrian Somers
827c11e57a3SBrian Somers dl->dial.tries = 0;
828565e35e5SBrian Somers dl->cfg.dial.max = 1;
829565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
830565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT;
831c11e57a3SBrian Somers dl->cfg.dial.inc = 0;
832c11e57a3SBrian Somers dl->cfg.dial.maxinc = 10;
833e718d1d7SBrian Somers
834abff9baeSBrian Somers dl->reconnect_tries = 0;
835565e35e5SBrian Somers dl->cfg.reconnect.max = 0;
836565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
837abff9baeSBrian Somers
83892b09558SBrian Somers dl->cfg.callback.opmask = 0;
83992b09558SBrian Somers dl->cfg.cbcp.delay = 0;
84092b09558SBrian Somers *dl->cfg.cbcp.phone = '\0';
84192b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY;
84292b09558SBrian Somers
8433006ec67SBrian Somers dl->name = strdup(name);
844643f4904SBrian Somers peerid_Init(&dl->peer);
8456f384573SBrian Somers dl->parent = &bundle->fsm;
8463b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart;
8473b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp;
8483b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown;
8493b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish;
8503b0f8d2eSBrian Somers dl->fsmp.object = dl;
8513b0f8d2eSBrian Somers
8525d9e6103SBrian Somers if ((dl->physical = physical_Create(dl, type)) == NULL) {
8533006ec67SBrian Somers free(dl->name);
8543006ec67SBrian Somers free(dl);
8553006ec67SBrian Somers return NULL;
8563006ec67SBrian Somers }
857f0cdd9c0SBrian Somers
858f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical);
859f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical);
86092b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical);
861c116e0c0SBrian Somers
862c116e0c0SBrian Somers memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */
863ffcfaec7SBrian Somers chat_Init(&dl->chat, dl->physical);
8643006ec67SBrian Somers
8659ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n",
8669ae58882SBrian Somers dl->name, datalink_State(dl));
8673006ec67SBrian Somers
8683006ec67SBrian Somers return dl;
8693006ec67SBrian Somers }
8703006ec67SBrian Somers
8713006ec67SBrian Somers struct datalink *
datalink_Clone(struct datalink * odl,const char * name)872cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name)
873cd7bd93aSBrian Somers {
874cd7bd93aSBrian Somers struct datalink *dl;
875cd7bd93aSBrian Somers
876cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink));
877cd7bd93aSBrian Somers if (dl == NULL)
878cd7bd93aSBrian Somers return dl;
879cd7bd93aSBrian Somers
880cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR;
881cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet;
882cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet;
883cd7bd93aSBrian Somers dl->desc.Read = datalink_Read;
884cd7bd93aSBrian Somers dl->desc.Write = datalink_Write;
885cd7bd93aSBrian Somers
886cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED;
887cd7bd93aSBrian Somers
888cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
889cd7bd93aSBrian Somers mp_linkInit(&dl->mp);
890cd7bd93aSBrian Somers *dl->phone.list = '\0';
891643f4904SBrian Somers dl->phone.next = NULL;
892643f4904SBrian Somers dl->phone.alt = NULL;
893643f4904SBrian Somers dl->phone.chosen = "N/A";
894cd7bd93aSBrian Somers dl->bundle = odl->bundle;
895cd7bd93aSBrian Somers dl->next = NULL;
896c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
897c11e57a3SBrian Somers dl->dial.tries = 0;
898cd7bd93aSBrian Somers dl->reconnect_tries = 0;
899cd7bd93aSBrian Somers dl->name = strdup(name);
900643f4904SBrian Somers peerid_Init(&dl->peer);
901cd7bd93aSBrian Somers dl->parent = odl->parent;
902cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
903643f4904SBrian Somers dl->fsmp.object = dl;
904cd7bd93aSBrian Somers
9055d9e6103SBrian Somers if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) {
906cd7bd93aSBrian Somers free(dl->name);
907cd7bd93aSBrian Somers free(dl);
908cd7bd93aSBrian Somers return NULL;
909cd7bd93aSBrian Somers }
910f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical);
911479508cfSBrian Somers dl->pap.cfg = odl->pap.cfg;
912f0cdd9c0SBrian Somers
913f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical);
914479508cfSBrian Somers dl->chap.auth.cfg = odl->chap.auth.cfg;
915f0cdd9c0SBrian Somers
916cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
917cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
918cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg);
919cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
920cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg);
921cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
922cd7bd93aSBrian Somers sizeof dl->physical->async.cfg);
923cd7bd93aSBrian Somers
92492b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical);
925c116e0c0SBrian Somers
926c116e0c0SBrian Somers memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */
927ffcfaec7SBrian Somers chat_Init(&dl->chat, dl->physical);
928cd7bd93aSBrian Somers
9299ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n",
9309ae58882SBrian Somers dl->name, datalink_State(dl));
931cd7bd93aSBrian Somers
932cd7bd93aSBrian Somers return dl;
933cd7bd93aSBrian Somers }
934cd7bd93aSBrian Somers
935cd7bd93aSBrian Somers struct datalink *
datalink_Destroy(struct datalink * dl)9363006ec67SBrian Somers datalink_Destroy(struct datalink *dl)
9373006ec67SBrian Somers {
9383006ec67SBrian Somers struct datalink *result;
9393006ec67SBrian Somers
94039d94652SBrian Somers if (dl->state != DATALINK_CLOSED) {
941dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n",
942c7cc5030SBrian Somers datalink_State(dl));
94339d94652SBrian Somers switch (dl->state) {
94439d94652SBrian Somers case DATALINK_HANGUP:
94539d94652SBrian Somers case DATALINK_DIAL:
94639d94652SBrian Somers case DATALINK_LOGIN:
947ffcfaec7SBrian Somers chat_Finish(&dl->chat); /* Gotta blat the timers ! */
94839d94652SBrian Somers break;
94939d94652SBrian Somers }
95039d94652SBrian Somers }
9513006ec67SBrian Somers
952ffcfaec7SBrian Somers chat_Destroy(&dl->chat);
953c11e57a3SBrian Somers timer_Stop(&dl->dial.timer);
9543006ec67SBrian Somers result = dl->next;
9555d9e6103SBrian Somers physical_Destroy(dl->physical);
9563006ec67SBrian Somers free(dl->name);
9573006ec67SBrian Somers free(dl);
9583006ec67SBrian Somers
9593006ec67SBrian Somers return result;
9603006ec67SBrian Somers }
9613006ec67SBrian Somers
9623006ec67SBrian Somers void
datalink_Up(struct datalink * dl,int runscripts,int packetmode)963c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode)
9643006ec67SBrian Somers {
9659603d5b4SBrian Somers if (!Enabled(dl->bundle, OPT_FORCE_SCRIPTS) &&
9669603d5b4SBrian Somers (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)))
967565e35e5SBrian Somers /* Ignore scripts */
968565e35e5SBrian Somers runscripts = 0;
969565e35e5SBrian Somers
970c7cc5030SBrian Somers switch (dl->state) {
971c7cc5030SBrian Somers case DATALINK_CLOSED:
9723b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
9733b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE)
9743b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
9759ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING);
976565e35e5SBrian Somers dl->reconnect_tries =
9776f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max;
978c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max;
979c5a5a6caSBrian Somers dl->script.run = runscripts;
980c5a5a6caSBrian Somers dl->script.packetmode = packetmode;
981c7cc5030SBrian Somers break;
982c7cc5030SBrian Somers
983c7cc5030SBrian Somers case DATALINK_OPENING:
984c7cc5030SBrian Somers if (!dl->script.run && runscripts)
985c7cc5030SBrian Somers dl->script.run = 1;
986f0067240SPhilippe Charnier /* FALLTHROUGH */
987c7cc5030SBrian Somers
988c7cc5030SBrian Somers case DATALINK_DIAL:
989c7cc5030SBrian Somers case DATALINK_LOGIN:
990c7cc5030SBrian Somers case DATALINK_READY:
991c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) {
992c7cc5030SBrian Somers dl->script.packetmode = 1;
9935e269efeSBrian Somers if (dl->state == DATALINK_READY) {
9945e269efeSBrian Somers dl->script.run = 0;
9955e269efeSBrian Somers datalink_NewState(dl, DATALINK_CARRIER);
9965e269efeSBrian Somers }
997c7cc5030SBrian Somers }
998c7cc5030SBrian Somers break;
9993006ec67SBrian Somers }
10003006ec67SBrian Somers }
10013006ec67SBrian Somers
10023006ec67SBrian Somers void
datalink_Close(struct datalink * dl,int how)10039c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how)
1004c7cc5030SBrian Somers {
1005c7cc5030SBrian Somers /* Please close */
1006e2ebb036SBrian Somers switch (dl->state) {
1007e2ebb036SBrian Somers case DATALINK_OPEN:
1008643f4904SBrian Somers peerid_Init(&dl->peer);
100909206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm);
1010f0067240SPhilippe Charnier /* FALLTHROUGH */
1011e2ebb036SBrian Somers
101292b09558SBrian Somers case DATALINK_CBCP:
1013e2ebb036SBrian Somers case DATALINK_AUTH:
1014e2ebb036SBrian Somers case DATALINK_LCP:
101564cfdfc6SBrian Somers datalink_AuthReInit(dl);
10169c81b87dSBrian Somers if (how == CLOSE_LCP)
10172fc2f705SBrian Somers datalink_DontHangup(dl);
10182fc2f705SBrian Somers else if (how == CLOSE_STAYDOWN)
10192fc2f705SBrian Somers datalink_StayDown(dl);
10202fc2f705SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm);
1021d81ecf9aSBrian Somers break;
1022e2ebb036SBrian Somers
1023e2ebb036SBrian Somers default:
10249c81b87dSBrian Somers datalink_ComeDown(dl, how);
1025c7cc5030SBrian Somers }
1026e2ebb036SBrian Somers }
1027c7cc5030SBrian Somers
1028c7cc5030SBrian Somers void
datalink_Down(struct datalink * dl,int how)10299c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how)
1030c7cc5030SBrian Somers {
1031c7cc5030SBrian Somers /* Carrier is lost */
1032e2ebb036SBrian Somers switch (dl->state) {
1033e2ebb036SBrian Somers case DATALINK_OPEN:
1034643f4904SBrian Somers peerid_Init(&dl->peer);
103509206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm);
1036f0067240SPhilippe Charnier /* FALLTHROUGH */
1037e2ebb036SBrian Somers
103892b09558SBrian Somers case DATALINK_CBCP:
1039e2ebb036SBrian Somers case DATALINK_AUTH:
1040e2ebb036SBrian Somers case DATALINK_LCP:
104109206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm);
1042225e259dSBrian Somers if (dl->state == DATALINK_OPENING)
1043225e259dSBrian Somers return; /* we're doing a callback... */
1044f0067240SPhilippe Charnier /* FALLTHROUGH */
1045c7cc5030SBrian Somers
1046e2ebb036SBrian Somers default:
10479c81b87dSBrian Somers datalink_ComeDown(dl, how);
1048c7cc5030SBrian Somers }
1049e2ebb036SBrian Somers }
1050c7cc5030SBrian Somers
1051c7cc5030SBrian Somers void
datalink_StayDown(struct datalink * dl)10523006ec67SBrian Somers datalink_StayDown(struct datalink *dl)
10533006ec67SBrian Somers {
10542fc2f705SBrian Somers dl->dial.tries = -1;
10553006ec67SBrian Somers dl->reconnect_tries = 0;
10562fc2f705SBrian Somers dl->stayonline = 0;
10573006ec67SBrian Somers }
1058c7cc5030SBrian Somers
10599c81b87dSBrian Somers void
datalink_DontHangup(struct datalink * dl)10609c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl)
10619c81b87dSBrian Somers {
10622fc2f705SBrian Somers dl->dial.tries = -1;
10632fc2f705SBrian Somers dl->reconnect_tries = 0;
10642fc2f705SBrian Somers dl->stayonline = dl->state >= DATALINK_LCP ? 1 : 0;
10659c81b87dSBrian Somers }
10669c81b87dSBrian Somers
1067643f4904SBrian Somers int
datalink_Show(struct cmdargs const * arg)1068643f4904SBrian Somers datalink_Show(struct cmdargs const *arg)
1069c7cc5030SBrian Somers {
1070643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
1071643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n",
1072643f4904SBrian Somers datalink_State(arg->cx));
1073643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: ");
1074643f4904SBrian Somers if (*arg->cx->peer.authname)
1075643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname);
1076643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN)
1077643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n");
1078565e35e5SBrian Somers else
1079643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n");
1080643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n",
1081643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class,
1082643f4904SBrian Somers arg->cx->peer.enddisc.address,
1083643f4904SBrian Somers arg->cx->peer.enddisc.len));
1084643f4904SBrian Somers
1085643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n");
1086643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n",
1087643f4904SBrian Somers arg->cx->cfg.phone.list);
1088643f4904SBrian Somers if (arg->cx->cfg.dial.max)
1089643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ",
1090643f4904SBrian Somers arg->cx->cfg.dial.max);
1091565e35e5SBrian Somers else
1092643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay ");
1093b5c347a3SBrian Somers if (arg->cx->cfg.dial.next_timeout >= 0)
1094643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout);
1095565e35e5SBrian Somers else
1096643f4904SBrian Somers prompt_Printf(arg->prompt, "random/");
1097b5c347a3SBrian Somers if (arg->cx->cfg.dial.timeout >= 0)
1098643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout);
1099565e35e5SBrian Somers else
1100643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n");
1101643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ",
1102643f4904SBrian Somers arg->cx->cfg.reconnect.max);
1103643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0)
1104643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout);
1105643f4904SBrian Somers else
1106643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n");
110792b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type ==
110892b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:");
110992b09558SBrian Somers if (!arg->cx->cfg.callback.opmask)
111092b09558SBrian Somers prompt_Printf(arg->prompt, "none\n");
111192b09558SBrian Somers else {
111292b09558SBrian Somers int comma = 0;
111392b09558SBrian Somers
111492b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
111592b09558SBrian Somers prompt_Printf(arg->prompt, "none");
111692b09558SBrian Somers comma = 1;
111792b09558SBrian Somers }
111892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
111992b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : "");
112092b09558SBrian Somers comma = 1;
112192b09558SBrian Somers }
112292b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
112392b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : "");
112492b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT)
112592b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg);
112692b09558SBrian Somers comma = 1;
112792b09558SBrian Somers }
112892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
112992b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : "");
113092b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n",
113192b09558SBrian Somers arg->cx->cfg.cbcp.delay);
1132cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: ");
1133cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) {
1134cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT)
1135cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n");
1136cf784a89SBrian Somers else
1137cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n");
1138cf784a89SBrian Somers } else
1139cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone);
114092b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n",
114192b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry);
114292b09558SBrian Somers } else
114392b09558SBrian Somers prompt_Printf(arg->prompt, "\n");
114492b09558SBrian Somers }
114592b09558SBrian Somers
1146643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n",
1147643f4904SBrian Somers arg->cx->cfg.script.dial);
1148643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n",
1149643f4904SBrian Somers arg->cx->cfg.script.login);
1150c116e0c0SBrian Somers prompt_Printf(arg->prompt, " Logout Script: %s\n",
1151c116e0c0SBrian Somers arg->cx->cfg.script.logout);
1152643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n",
1153643f4904SBrian Somers arg->cx->cfg.script.hangup);
1154643f4904SBrian Somers return 0;
1155565e35e5SBrian Somers }
1156565e35e5SBrian Somers
1157565e35e5SBrian Somers int
datalink_SetReconnect(struct cmdargs const * arg)1158565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg)
1159565e35e5SBrian Somers {
116025092092SBrian Somers if (arg->argc == arg->argn+2) {
116125092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]);
116225092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]);
1163565e35e5SBrian Somers return 0;
1164565e35e5SBrian Somers }
1165565e35e5SBrian Somers return -1;
1166565e35e5SBrian Somers }
1167565e35e5SBrian Somers
1168565e35e5SBrian Somers int
datalink_SetRedial(struct cmdargs const * arg)1169565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg)
1170565e35e5SBrian Somers {
1171c11e57a3SBrian Somers const char *sep, *osep;
1172c11e57a3SBrian Somers int timeout, inc, maxinc, tries;
1173565e35e5SBrian Somers
117425092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) {
117525092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 &&
117625092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) {
1177565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1;
1178565e35e5SBrian Somers randinit();
1179565e35e5SBrian Somers } else {
118025092092SBrian Somers timeout = atoi(arg->argv[arg->argn]);
1181565e35e5SBrian Somers
1182565e35e5SBrian Somers if (timeout >= 0)
1183565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout;
1184565e35e5SBrian Somers else {
1185dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n");
1186565e35e5SBrian Somers return -1;
1187565e35e5SBrian Somers }
1188565e35e5SBrian Somers }
1189565e35e5SBrian Somers
1190c11e57a3SBrian Somers sep = strchr(arg->argv[arg->argn], '+');
1191c11e57a3SBrian Somers if (sep) {
1192c11e57a3SBrian Somers inc = atoi(++sep);
1193c11e57a3SBrian Somers osep = sep;
1194c11e57a3SBrian Somers if (inc >= 0)
1195c11e57a3SBrian Somers arg->cx->cfg.dial.inc = inc;
1196c11e57a3SBrian Somers else {
1197c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid timeout increment\n");
1198c11e57a3SBrian Somers return -1;
1199c11e57a3SBrian Somers }
1200c11e57a3SBrian Somers sep = strchr(sep, '-');
1201c11e57a3SBrian Somers if (sep) {
1202c11e57a3SBrian Somers maxinc = atoi(++sep);
1203c11e57a3SBrian Somers if (maxinc >= 0)
1204c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = maxinc;
1205c11e57a3SBrian Somers else {
1206c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid maximum timeout increments\n");
1207c11e57a3SBrian Somers return -1;
1208c11e57a3SBrian Somers }
1209c11e57a3SBrian Somers } else {
1210c11e57a3SBrian Somers /* Default timeout increment */
1211c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10;
1212c11e57a3SBrian Somers sep = osep;
1213c11e57a3SBrian Somers }
1214c11e57a3SBrian Somers } else {
1215c11e57a3SBrian Somers /* Default timeout increment & max increment */
1216c11e57a3SBrian Somers arg->cx->cfg.dial.inc = 0;
1217c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10;
1218c11e57a3SBrian Somers sep = arg->argv[arg->argn];
1219c11e57a3SBrian Somers }
1220c11e57a3SBrian Somers
1221c11e57a3SBrian Somers sep = strchr(sep, '.');
1222c11e57a3SBrian Somers if (sep) {
1223c11e57a3SBrian Somers if (strcasecmp(++sep, "random") == 0) {
1224565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1;
1225565e35e5SBrian Somers randinit();
1226565e35e5SBrian Somers } else {
1227c11e57a3SBrian Somers timeout = atoi(sep);
1228565e35e5SBrian Somers if (timeout >= 0)
1229565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout;
1230565e35e5SBrian Somers else {
1231dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n");
1232565e35e5SBrian Somers return -1;
1233565e35e5SBrian Somers }
1234565e35e5SBrian Somers }
1235565e35e5SBrian Somers } else
1236565e35e5SBrian Somers /* Default next timeout */
1237565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
1238565e35e5SBrian Somers
123925092092SBrian Somers if (arg->argc == arg->argn+2) {
124025092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]);
1241565e35e5SBrian Somers
1242565e35e5SBrian Somers if (tries >= 0) {
1243565e35e5SBrian Somers arg->cx->cfg.dial.max = tries;
1244565e35e5SBrian Somers } else {
1245dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n");
1246565e35e5SBrian Somers return 1;
1247565e35e5SBrian Somers }
1248565e35e5SBrian Somers }
1249565e35e5SBrian Somers return 0;
1250565e35e5SBrian Somers }
1251c11e57a3SBrian Somers
1252565e35e5SBrian Somers return -1;
1253c7cc5030SBrian Somers }
1254c7cc5030SBrian Somers
1255182c898aSBrian Somers static const char * const states[] = {
1256565e35e5SBrian Somers "closed",
1257565e35e5SBrian Somers "opening",
1258565e35e5SBrian Somers "hangup",
1259565e35e5SBrian Somers "dial",
1260eb6e5e05SBrian Somers "carrier",
1261c116e0c0SBrian Somers "logout",
1262565e35e5SBrian Somers "login",
1263565e35e5SBrian Somers "ready",
1264565e35e5SBrian Somers "lcp",
1265565e35e5SBrian Somers "auth",
126692b09558SBrian Somers "cbcp",
1267565e35e5SBrian Somers "open"
1268c7cc5030SBrian Somers };
1269c7cc5030SBrian Somers
1270643f4904SBrian Somers const char *
datalink_State(struct datalink * dl)1271c7cc5030SBrian Somers datalink_State(struct datalink *dl)
1272c7cc5030SBrian Somers {
1273057f1760SBrian Somers if (dl->state >= sizeof states / sizeof states[0])
1274c7cc5030SBrian Somers return "unknown";
1275c7cc5030SBrian Somers return states[dl->state];
1276c7cc5030SBrian Somers }
12776f384573SBrian Somers
12789ae58882SBrian Somers static void
datalink_NewState(struct datalink * dl,unsigned state)1279057f1760SBrian Somers datalink_NewState(struct datalink *dl, unsigned state)
12809ae58882SBrian Somers {
12819ae58882SBrian Somers if (state != dl->state) {
1282057f1760SBrian Somers if (state < sizeof states / sizeof states[0]) {
12839ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl),
12849ae58882SBrian Somers states[state]);
12859ae58882SBrian Somers dl->state = state;
12869ae58882SBrian Somers } else
12879ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state);
12889ae58882SBrian Somers }
12899ae58882SBrian Somers }
12909ae58882SBrian Somers
12916f384573SBrian Somers struct datalink *
iov2datalink(struct bundle * bundle,struct iovec * iov,int * niov,int maxiov,int fd,int * auxfd,int * nauxfd)129296c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov,
129387c3786eSBrian Somers int fd, int *auxfd, int *nauxfd)
12946f384573SBrian Somers {
1295b7c5748eSBrian Somers struct datalink *dl, *cdl;
1296479508cfSBrian Somers struct fsm_retry copy;
12975d604c11SBrian Somers char *oname, *pname;
12986f384573SBrian Somers
129996c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base;
130096c9bb21SBrian Somers dl->name = iov[*niov].iov_base;
13016f384573SBrian Somers
130296c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) {
130396c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0';
130496c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1)
130596c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name);
13066f384573SBrian Somers }
1307b7c5748eSBrian Somers
1308b7c5748eSBrian Somers /* Make sure the name is unique ! */
1309b7c5748eSBrian Somers oname = NULL;
1310b7c5748eSBrian Somers do {
1311b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next)
1312b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) {
13135d604c11SBrian Somers if ((pname = datalink_NextName(dl)) == NULL) {
13145d604c11SBrian Somers for ((*niov)--; *niov < maxiov; (*niov)++)
13155d604c11SBrian Somers free(iov[*niov].iov_base);
13165d604c11SBrian Somers return NULL;
13175d604c11SBrian Somers } else if (oname)
13185d604c11SBrian Somers free(pname);
1319b7c5748eSBrian Somers else
13205d604c11SBrian Somers oname = pname;
1321b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */
1322b7c5748eSBrian Somers }
1323b7c5748eSBrian Somers } while (cdl);
1324b7c5748eSBrian Somers
1325b7c5748eSBrian Somers if (oname) {
1326b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name);
1327b7c5748eSBrian Somers free(oname);
1328b7c5748eSBrian Somers } else {
132996c9bb21SBrian Somers dl->name = strdup(dl->name);
1330b7c5748eSBrian Somers free(iov[*niov].iov_base);
1331b7c5748eSBrian Somers }
1332b7c5748eSBrian Somers (*niov)++;
13336f384573SBrian Somers
13346f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR;
13356f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet;
13366f384573SBrian Somers dl->desc.IsSet = datalink_IsSet;
13376f384573SBrian Somers dl->desc.Read = datalink_Read;
13386f384573SBrian Somers dl->desc.Write = datalink_Write;
13396f384573SBrian Somers
13406f384573SBrian Somers mp_linkInit(&dl->mp);
13416f384573SBrian Somers *dl->phone.list = '\0';
13426f384573SBrian Somers dl->phone.next = NULL;
13436f384573SBrian Somers dl->phone.alt = NULL;
13446f384573SBrian Somers dl->phone.chosen = "N/A";
13456f384573SBrian Somers
13466f384573SBrian Somers dl->bundle = bundle;
13476f384573SBrian Somers dl->next = NULL;
1348c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
1349c11e57a3SBrian Somers dl->dial.tries = 0;
13506f384573SBrian Somers dl->reconnect_tries = 0;
13516f384573SBrian Somers dl->parent = &bundle->fsm;
13526f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart;
13536f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp;
13546f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown;
13556f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish;
13566f384573SBrian Somers dl->fsmp.object = dl;
13576f384573SBrian Somers
135887c3786eSBrian Somers dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd);
135996c9bb21SBrian Somers
136096c9bb21SBrian Somers if (!dl->physical) {
13616f384573SBrian Somers free(dl->name);
13626f384573SBrian Somers free(dl);
13636f384573SBrian Somers dl = NULL;
13649ae58882SBrian Somers } else {
1365479508cfSBrian Somers copy = dl->pap.cfg.fsm;
1366f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical);
1367479508cfSBrian Somers dl->pap.cfg.fsm = copy;
1368f0cdd9c0SBrian Somers
1369479508cfSBrian Somers copy = dl->chap.auth.cfg.fsm;
1370f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical);
1371479508cfSBrian Somers dl->chap.auth.cfg.fsm = copy;
1372f0cdd9c0SBrian Somers
137392b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical);
1374c116e0c0SBrian Somers
1375c116e0c0SBrian Somers memset(&dl->chat, '\0', sizeof dl->chat); /* Force buf{start,end} reset */
1376ffcfaec7SBrian Somers chat_Init(&dl->chat, dl->physical);
13776f384573SBrian Somers
13789ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n",
13799ae58882SBrian Somers dl->name, datalink_State(dl));
13809ae58882SBrian Somers }
13819ae58882SBrian Somers
13826f384573SBrian Somers return dl;
13836f384573SBrian Somers }
13846f384573SBrian Somers
13856f384573SBrian Somers int
datalink2iov(struct datalink * dl,struct iovec * iov,int * niov,int maxiov,int * auxfd,int * nauxfd)138685fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
13872cb305afSBrian Somers int *auxfd, int *nauxfd)
13886f384573SBrian Somers {
138996c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */
139096c9bb21SBrian Somers int link_fd;
13916f384573SBrian Somers
139296c9bb21SBrian Somers if (dl) {
1393c11e57a3SBrian Somers timer_Stop(&dl->dial.timer);
139492b09558SBrian Somers /* The following is purely for the sake of paranoia */
139592b09558SBrian Somers cbcp_Down(&dl->cbcp);
1396dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer);
1397dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer);
13986f384573SBrian Somers }
13996f384573SBrian Somers
140096c9bb21SBrian Somers if (*niov >= maxiov - 1) {
140196c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n");
140296c9bb21SBrian Somers if (dl) {
14036f384573SBrian Somers free(dl->name);
14046f384573SBrian Somers free(dl);
140596c9bb21SBrian Somers }
140696c9bb21SBrian Somers return -1;
140796c9bb21SBrian Somers }
140896c9bb21SBrian Somers
14092cb305afSBrian Somers iov[*niov].iov_base = (void *)dl;
141096c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl;
14112cb305afSBrian Somers iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL;
141296c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME;
141396c9bb21SBrian Somers
141487c3786eSBrian Somers link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd,
14152cb305afSBrian Somers nauxfd);
141696c9bb21SBrian Somers
141796c9bb21SBrian Somers if (link_fd == -1 && dl) {
141896c9bb21SBrian Somers free(dl->name);
141996c9bb21SBrian Somers free(dl);
142096c9bb21SBrian Somers }
14216f384573SBrian Somers
14226f384573SBrian Somers return link_fd;
14236f384573SBrian Somers }
14246f384573SBrian Somers
142558d55334SBrian Somers void
datalink_Rename(struct datalink * dl,const char * name)142658d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name)
142758d55334SBrian Somers {
142858d55334SBrian Somers free(dl->name);
142958d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name);
143058d55334SBrian Somers }
143158d55334SBrian Somers
14325d604c11SBrian Somers static char *
datalink_NextName(struct datalink * dl)143384917b87SBrian Somers datalink_NextName(struct datalink *dl)
14346f384573SBrian Somers {
14356f384573SBrian Somers int f, n;
143684917b87SBrian Somers char *name, *oname;
14376f384573SBrian Somers
14386f384573SBrian Somers n = strlen(dl->name);
14395d604c11SBrian Somers if ((name = (char *)malloc(n+3)) == NULL) {
14405d604c11SBrian Somers log_Printf(LogERROR, "datalink_NextName: Out of memory !\n");
14415d604c11SBrian Somers return NULL;
14425d604c11SBrian Somers }
14436f384573SBrian Somers for (f = n - 1; f >= 0; f--)
14446f384573SBrian Somers if (!isdigit(dl->name[f]))
14456f384573SBrian Somers break;
14466f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name);
14476f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1);
144884917b87SBrian Somers oname = dl->name;
144954cd8e13SBrian Somers dl->name = name;
145054cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */
145184917b87SBrian Somers return oname;
14526f384573SBrian Somers }
1453dd0645c5SBrian Somers
1454dd0645c5SBrian Somers int
datalink_SetMode(struct datalink * dl,int mode)1455dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode)
1456dd0645c5SBrian Somers {
1457dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode))
1458dd0645c5SBrian Somers return 0;
1459dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
1460dd0645c5SBrian Somers dl->script.run = 0;
1461dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT)
1462dd0645c5SBrian Somers dl->reconnect_tries = 0;
1463f6a4e748SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) &&
1464f6a4e748SBrian Somers dl->state <= DATALINK_READY)
1465dd0645c5SBrian Somers datalink_Up(dl, 1, 1);
1466dd0645c5SBrian Somers return 1;
1467dd0645c5SBrian Somers }
1468c11e57a3SBrian Somers
1469c11e57a3SBrian Somers int
datalink_GetDialTimeout(struct datalink * dl)1470c11e57a3SBrian Somers datalink_GetDialTimeout(struct datalink *dl)
1471c11e57a3SBrian Somers {
1472c11e57a3SBrian Somers int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc;
1473c11e57a3SBrian Somers
1474c11e57a3SBrian Somers if (dl->dial.incs < dl->cfg.dial.maxinc)
1475c11e57a3SBrian Somers dl->dial.incs++;
1476c11e57a3SBrian Somers
1477c11e57a3SBrian Somers return result;
1478c11e57a3SBrian Somers }
1479