xref: /freebsd/usr.sbin/ppp/datalink.c (revision b3e76948)
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