xref: /freebsd/usr.sbin/ppp/datalink.c (revision a65be227)
13006ec67SBrian Somers /*-
23006ec67SBrian Somers  * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
33006ec67SBrian Somers  * All rights reserved.
43006ec67SBrian Somers  *
53006ec67SBrian Somers  * Redistribution and use in source and binary forms, with or without
63006ec67SBrian Somers  * modification, are permitted provided that the following conditions
73006ec67SBrian Somers  * are met:
83006ec67SBrian Somers  * 1. Redistributions of source code must retain the above copyright
93006ec67SBrian Somers  *    notice, this list of conditions and the following disclaimer.
103006ec67SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
113006ec67SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
123006ec67SBrian Somers  *    documentation and/or other materials provided with the distribution.
133006ec67SBrian Somers  *
143006ec67SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153006ec67SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163006ec67SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173006ec67SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183006ec67SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193006ec67SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203006ec67SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213006ec67SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223006ec67SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233006ec67SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243006ec67SBrian Somers  * SUCH DAMAGE.
253006ec67SBrian Somers  *
2697d92980SPeter Wemm  * $FreeBSD$
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>
331fa665f5SBrian Somers #include <sys/un.h>
343006ec67SBrian Somers 
356f384573SBrian Somers #include <ctype.h>
36c7cc5030SBrian Somers #include <stdio.h>
373006ec67SBrian Somers #include <stdlib.h>
383006ec67SBrian Somers #include <string.h>
3996c9bb21SBrian Somers #include <sys/uio.h>
403006ec67SBrian Somers #include <termios.h>
413006ec67SBrian Somers 
425d9e6103SBrian Somers #include "layer.h"
433006ec67SBrian Somers #include "mbuf.h"
443006ec67SBrian Somers #include "log.h"
453006ec67SBrian Somers #include "defs.h"
463006ec67SBrian Somers #include "timer.h"
473006ec67SBrian Somers #include "fsm.h"
483006ec67SBrian Somers #include "descriptor.h"
49879ed6faSBrian Somers #include "lqr.h"
503006ec67SBrian Somers #include "hdlc.h"
511038894eSBrian Somers #include "lcp.h"
523006ec67SBrian Somers #include "async.h"
533006ec67SBrian Somers #include "throughput.h"
543b0f8d2eSBrian Somers #include "ccp.h"
553006ec67SBrian Somers #include "link.h"
563006ec67SBrian Somers #include "physical.h"
575828db6dSBrian Somers #include "iplist.h"
58eaa4df37SBrian Somers #include "slcompress.h"
595828db6dSBrian Somers #include "ipcp.h"
605ca5389aSBrian Somers #include "filter.h"
613b0f8d2eSBrian Somers #include "mp.h"
62972a1bcfSBrian Somers #ifndef NORADIUS
63972a1bcfSBrian Somers #include "radius.h"
64972a1bcfSBrian Somers #endif
653006ec67SBrian Somers #include "bundle.h"
663006ec67SBrian Somers #include "chat.h"
67e2ebb036SBrian Somers #include "auth.h"
68c7cc5030SBrian Somers #include "prompt.h"
695d9e6103SBrian Somers #include "proto.h"
70e2ebb036SBrian Somers #include "pap.h"
71e2ebb036SBrian Somers #include "chap.h"
72565e35e5SBrian Somers #include "command.h"
7392b09558SBrian Somers #include "cbcp.h"
74e2ebb036SBrian Somers #include "datalink.h"
75c7cc5030SBrian Somers 
76030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *);
779ae58882SBrian Somers static void datalink_NewState(struct datalink *, int);
783006ec67SBrian Somers 
793006ec67SBrian Somers static void
803006ec67SBrian Somers datalink_OpenTimeout(void *v)
813006ec67SBrian Somers {
823006ec67SBrian Somers   struct datalink *dl = (struct datalink *)v;
833006ec67SBrian Somers 
84c11e57a3SBrian Somers   timer_Stop(&dl->dial.timer);
853006ec67SBrian Somers   if (dl->state == DATALINK_OPENING)
86b42135deSBrian Somers     log_Printf(LogCHAT, "%s: Redial timer expired.\n", dl->name);
873006ec67SBrian Somers }
883006ec67SBrian Somers 
89b5c347a3SBrian Somers static int
903006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout)
913006ec67SBrian Somers {
92b5c347a3SBrian Somers   int result = Timeout;
933006ec67SBrian Somers 
94c11e57a3SBrian Somers   timer_Stop(&dl->dial.timer);
953006ec67SBrian Somers   if (Timeout) {
96a65be227SBrian Somers     if (Timeout < 0)
97b5c347a3SBrian Somers       result = (random() % DIAL_TIMEOUT) + 1;
98c11e57a3SBrian Somers     dl->dial.timer.load = result * SECTICKS;
99c11e57a3SBrian Somers     dl->dial.timer.func = datalink_OpenTimeout;
100c11e57a3SBrian Somers     dl->dial.timer.name = "dial";
101c11e57a3SBrian Somers     dl->dial.timer.arg = dl;
102c11e57a3SBrian Somers     timer_Start(&dl->dial.timer);
1033006ec67SBrian Somers     if (dl->state == DATALINK_OPENING)
104dd7e2610SBrian Somers       log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
105a65be227SBrian Somers                 dl->name, result);
1063006ec67SBrian Somers   }
107b5c347a3SBrian Somers   return result;
1083006ec67SBrian Somers }
1093006ec67SBrian Somers 
1103006ec67SBrian Somers static void
1113006ec67SBrian Somers datalink_HangupDone(struct datalink *dl)
1123006ec67SBrian Somers {
113030e4ebbSBrian Somers   if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp &&
1145d9e6103SBrian Somers       dl->physical->fd != -1) {
1155d9e6103SBrian Somers     /* Don't close our device if the link is dedicated */
116030e4ebbSBrian Somers     datalink_LoginDone(dl);
117030e4ebbSBrian Somers     return;
118030e4ebbSBrian Somers   }
119030e4ebbSBrian Somers 
120ffcfaec7SBrian Somers   chat_Finish(&dl->chat);
1215d9e6103SBrian Somers   physical_Close(dl->physical);
122565e35e5SBrian Somers   dl->phone.chosen = "N/A";
1233006ec67SBrian Somers 
12492b09558SBrian Somers   if (dl->cbcp.required) {
12592b09558SBrian Somers     log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone);
12692b09558SBrian Somers     dl->cfg.callback.opmask = 0;
12792b09558SBrian Somers     strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone,
12892b09558SBrian Somers             sizeof dl->cfg.phone.list - 1);
12992b09558SBrian Somers     dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0';
13092b09558SBrian Somers     dl->phone.alt = dl->phone.next = NULL;
13192b09558SBrian Somers     dl->reconnect_tries = dl->cfg.reconnect.max;
132c11e57a3SBrian Somers     dl->dial.tries = dl->cfg.dial.max;
133c11e57a3SBrian Somers     dl->dial.incs = 0;
13492b09558SBrian Somers     dl->script.run = 1;
13592b09558SBrian Somers     dl->script.packetmode = 1;
13692b09558SBrian Somers     if (!physical_SetMode(dl->physical, PHYS_BACKGROUND))
13792b09558SBrian Somers       log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n");
13892b09558SBrian Somers     bundle_LinksRemoved(dl->bundle);
139c11e57a3SBrian Somers     /* if dial.timeout is < 0 (random), we don't override fsm.delay */
14092b09558SBrian Somers     if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout)
14192b09558SBrian Somers       dl->cbcp.fsm.delay = dl->cfg.dial.timeout;
14292b09558SBrian Somers     datalink_StartDialTimer(dl, dl->cbcp.fsm.delay);
14392b09558SBrian Somers     cbcp_Down(&dl->cbcp);
14492b09558SBrian Somers     datalink_NewState(dl, DATALINK_OPENING);
1451b02dfb4SBrian Somers     if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
1461b02dfb4SBrian Somers         bundle_Phase(dl->bundle) == PHASE_TERMINATE)
1470ca6f91bSBrian Somers       bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
14892b09558SBrian Somers   } else if (dl->bundle->CleaningUp ||
1496f384573SBrian Somers       (dl->physical->type == PHYS_DIRECT) ||
150c11e57a3SBrian Somers       ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) &&
15181358fa3SBrian Somers        !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) {
1529ae58882SBrian Somers     datalink_NewState(dl, DATALINK_CLOSED);
153c11e57a3SBrian Somers     dl->dial.tries = -1;
154c11e57a3SBrian Somers     dl->dial.incs = 0;
1553006ec67SBrian Somers     dl->reconnect_tries = 0;
1563006ec67SBrian Somers     bundle_LinkClosed(dl->bundle, dl);
1574b567bf2SBrian Somers     if (!dl->bundle->CleaningUp &&
1584b567bf2SBrian Somers         !(dl->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)))
159c11e57a3SBrian Somers       datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
1603006ec67SBrian Somers   } else {
1619ae58882SBrian Somers     datalink_NewState(dl, DATALINK_OPENING);
1621b02dfb4SBrian Somers     if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
1631b02dfb4SBrian Somers         bundle_Phase(dl->bundle) == PHASE_TERMINATE)
1640ca6f91bSBrian Somers       bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
165c11e57a3SBrian Somers     if (dl->dial.tries < 0) {
166565e35e5SBrian Somers       datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
167c11e57a3SBrian Somers       dl->dial.tries = dl->cfg.dial.max;
168c11e57a3SBrian Somers       dl->dial.incs = 0;
169abff9baeSBrian Somers       dl->reconnect_tries--;
170b42135deSBrian Somers       log_Printf(LogCHAT, "%s: Reconnect try %d of %d\n",
171b42135deSBrian Somers                  dl->name, dl->cfg.reconnect.max - dl->reconnect_tries,
172b42135deSBrian Somers                  dl->cfg.reconnect.max);
173b42135deSBrian Somers       bundle_Notify(dl->bundle, EX_RECONNECT);
174abff9baeSBrian Somers     } else {
175f9545805SBrian Somers       if (dl->phone.next == NULL)
176c11e57a3SBrian Somers         datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
1773006ec67SBrian Somers       else
178565e35e5SBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
179b42135deSBrian Somers       bundle_Notify(dl->bundle, EX_REDIAL);
1803006ec67SBrian Somers     }
181abff9baeSBrian Somers   }
182abff9baeSBrian Somers }
1833006ec67SBrian Somers 
184eb6e5e05SBrian Somers const char *
185f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl)
186f9545805SBrian Somers {
187f9545805SBrian Somers   char *phone;
188f9545805SBrian Somers 
189f9545805SBrian Somers   if (dl->phone.alt == NULL) {
190f9545805SBrian Somers     if (dl->phone.next == NULL) {
191f9545805SBrian Somers       strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
192f9545805SBrian Somers       dl->phone.list[sizeof dl->phone.list - 1] = '\0';
19308da4867SBrian Somers       if (*dl->phone.list == '\0')
19408da4867SBrian Somers         return "";
195f9545805SBrian Somers       dl->phone.next = dl->phone.list;
196f9545805SBrian Somers     }
197f9545805SBrian Somers     dl->phone.alt = strsep(&dl->phone.next, ":");
198f9545805SBrian Somers   }
199f9545805SBrian Somers   phone = strsep(&dl->phone.alt, "|");
200f9545805SBrian Somers   dl->phone.chosen = *phone ? phone : "[NONE]";
201f9545805SBrian Somers   if (*phone)
202b42135deSBrian Somers     log_Printf(LogCHAT, "Phone: %s\n", phone);
203f9545805SBrian Somers   return phone;
204f9545805SBrian Somers }
205f9545805SBrian Somers 
206c5a5a6caSBrian Somers static void
207c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl)
208c5a5a6caSBrian Somers {
209ffcfaec7SBrian Somers   chat_Finish(&dl->chat);
210c116e0c0SBrian Somers 
211d345321bSBrian Somers   if (!dl->script.packetmode) {
212c11e57a3SBrian Somers     dl->dial.tries = -1;
213c11e57a3SBrian Somers     dl->dial.incs = 0;
2149ae58882SBrian Somers     datalink_NewState(dl, DATALINK_READY);
2155d9e6103SBrian Somers   } else if (!physical_Raw(dl->physical)) {
216c11e57a3SBrian Somers     dl->dial.tries = 0;
217dd7e2610SBrian Somers     log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n");
218c5a5a6caSBrian Somers     if (dl->script.run) {
219c116e0c0SBrian Somers       datalink_NewState(dl, DATALINK_LOGOUT);
220c39aa54eSBrian Somers       if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL))
221c39aa54eSBrian Somers         log_Printf(LogWARN, "Invalid logout script\n");
222030e4ebbSBrian Somers     } else {
2236815097bSBrian Somers       physical_StopDeviceTimer(dl->physical);
224030e4ebbSBrian Somers       if (dl->physical->type == PHYS_DEDICATED)
225030e4ebbSBrian Somers         /* force a redial timeout */
2265d9e6103SBrian Somers         physical_Close(dl->physical);
227c5a5a6caSBrian Somers       datalink_HangupDone(dl);
228030e4ebbSBrian Somers     }
229c5a5a6caSBrian Somers   } else {
230c11e57a3SBrian Somers     dl->dial.tries = -1;
231c11e57a3SBrian Somers     dl->dial.incs = 0;
232c7cc5030SBrian Somers 
233643f4904SBrian Somers     hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp);
2343b0f8d2eSBrian Somers     async_Init(&dl->physical->async);
2353b0f8d2eSBrian Somers 
236cd9647a1SBrian Somers     lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
237cd9647a1SBrian Somers               0 : dl->physical->link.lcp.cfg.openmode);
2383b0f8d2eSBrian Somers     ccp_Setup(&dl->physical->link.ccp);
239503a7782SBrian Somers 
2409ae58882SBrian Somers     datalink_NewState(dl, DATALINK_LCP);
241dd7e2610SBrian Somers     fsm_Up(&dl->physical->link.lcp.fsm);
242dd7e2610SBrian Somers     fsm_Open(&dl->physical->link.lcp.fsm);
243c5a5a6caSBrian Somers   }
244c5a5a6caSBrian Somers }
245c5a5a6caSBrian Somers 
2463006ec67SBrian Somers static int
247f013f33eSBrian Somers datalink_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e,
2483006ec67SBrian Somers                    int *n)
2493006ec67SBrian Somers {
2503006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
2513006ec67SBrian Somers   int result;
2523006ec67SBrian Somers 
253310c3babSBrian Somers   result = 0;
2543006ec67SBrian Somers   switch (dl->state) {
2553006ec67SBrian Somers     case DATALINK_CLOSED:
256f6a4e748SBrian Somers       if ((dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|
257f6a4e748SBrian Somers                                  PHYS_FOREGROUND|PHYS_DDIAL)) &&
258194c225dSBrian Somers           !dl->bundle->CleaningUp)
259565e35e5SBrian Somers         /*
26081358fa3SBrian Somers          * Our first time in - DEDICATED & DDIAL never come down, and
261f6a4e748SBrian Somers          * DIRECT, FOREGROUND & BACKGROUND get deleted when they enter
262f6a4e748SBrian Somers          * DATALINK_CLOSED.  Go to DATALINK_OPENING via datalink_Up()
263f6a4e748SBrian Somers          * and fall through.
264565e35e5SBrian Somers          */
265565e35e5SBrian Somers         datalink_Up(dl, 1, 1);
266565e35e5SBrian Somers       else
267310c3babSBrian Somers         break;
268565e35e5SBrian Somers       /* fall through */
2693006ec67SBrian Somers 
2703006ec67SBrian Somers     case DATALINK_OPENING:
271c11e57a3SBrian Somers       if (dl->dial.timer.state != TIMER_RUNNING) {
272c11e57a3SBrian Somers         if (--dl->dial.tries < 0)
273c11e57a3SBrian Somers           dl->dial.tries = 0;
2745d9e6103SBrian Somers         if (physical_Open(dl->physical, dl->bundle) >= 0) {
275bf1d3ff6SBrian Somers           log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n"
276bf1d3ff6SBrian Somers                            "Type `~?' for help\r\n", dl->name,
277bf1d3ff6SBrian Somers                            dl->physical->name.full);
278c5a5a6caSBrian Somers           if (dl->script.run) {
2799ae58882SBrian Somers             datalink_NewState(dl, DATALINK_DIAL);
280c39aa54eSBrian Somers             if (!chat_Setup(&dl->chat, dl->cfg.script.dial,
281c39aa54eSBrian Somers                             *dl->cfg.script.dial ?
282c39aa54eSBrian Somers                             datalink_ChoosePhoneNumber(dl) : ""))
283c39aa54eSBrian Somers               log_Printf(LogWARN, "Invalid dial script\n");
28481358fa3SBrian Somers             if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
285565e35e5SBrian Somers                 dl->cfg.dial.max)
286dd7e2610SBrian Somers               log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n",
287c11e57a3SBrian Somers                         dl->name, dl->cfg.dial.max - dl->dial.tries,
288565e35e5SBrian Somers                         dl->cfg.dial.max);
289c5a5a6caSBrian Somers           } else
29014e34a55SBrian Somers             datalink_NewState(dl, DATALINK_CARRIER);
2918b09cf1cSBrian Somers           return datalink_UpdateSet(d, r, w, e, n);
2923006ec67SBrian Somers         } else {
29381358fa3SBrian Somers           if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
294565e35e5SBrian Somers               dl->cfg.dial.max)
2955d9e6103SBrian Somers             log_Printf(LogCHAT, "Failed to open device (attempt %u of %d)\n",
296c11e57a3SBrian Somers                        dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max);
2973006ec67SBrian Somers           else
2985d9e6103SBrian Somers             log_Printf(LogCHAT, "Failed to open device\n");
2993006ec67SBrian Somers 
3003b0f8d2eSBrian Somers           if (dl->bundle->CleaningUp ||
30181358fa3SBrian Somers               (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
302c11e57a3SBrian Somers                dl->cfg.dial.max && dl->dial.tries == 0)) {
3039ae58882SBrian Somers             datalink_NewState(dl, DATALINK_CLOSED);
3043006ec67SBrian Somers             dl->reconnect_tries = 0;
305c11e57a3SBrian Somers             dl->dial.tries = -1;
306bf1d3ff6SBrian Somers             log_WritePrompts(dl, "Failed to open %s\n",
307bf1d3ff6SBrian Somers                              dl->physical->name.full);
3085b8b8060SBrian Somers             bundle_LinkClosed(dl->bundle, dl);
309c5a5a6caSBrian Somers           }
310bf1d3ff6SBrian Somers           if (!dl->bundle->CleaningUp) {
311c11e57a3SBrian Somers             int timeout;
312c11e57a3SBrian Somers 
313c11e57a3SBrian Somers             timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl));
314b42135deSBrian Somers             bundle_Notify(dl->bundle, EX_REDIAL);
315bf1d3ff6SBrian Somers             log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n",
316b5c347a3SBrian Somers                              dl->physical->name.full, timeout);
3173006ec67SBrian Somers           }
3183006ec67SBrian Somers         }
319bf1d3ff6SBrian Somers       }
320310c3babSBrian Somers       break;
3213006ec67SBrian Somers 
322eb6e5e05SBrian Somers     case DATALINK_CARRIER:
323eb6e5e05SBrian Somers       /* Wait for carrier on the device */
324eb6e5e05SBrian Somers       switch (physical_AwaitCarrier(dl->physical)) {
325eb6e5e05SBrian Somers         case CARRIER_PENDING:
326eb6e5e05SBrian Somers           log_Printf(LogDEBUG, "Waiting for carrier\n");
327eb6e5e05SBrian Somers           return 0;	/* A device timer is running to wake us up again */
328eb6e5e05SBrian Somers 
329eb6e5e05SBrian Somers         case CARRIER_OK:
33014e34a55SBrian Somers           if (dl->script.run) {
331eb6e5e05SBrian Somers             datalink_NewState(dl, DATALINK_LOGIN);
332c39aa54eSBrian Somers             if (!chat_Setup(&dl->chat, dl->cfg.script.login, NULL))
333c39aa54eSBrian Somers               log_Printf(LogWARN, "Invalid login script\n");
33414e34a55SBrian Somers           } else
33514e34a55SBrian Somers             datalink_LoginDone(dl);
336eb6e5e05SBrian Somers           return datalink_UpdateSet(d, r, w, e, n);
337eb6e5e05SBrian Somers 
338eb6e5e05SBrian Somers         case CARRIER_LOST:
339eb6e5e05SBrian Somers           physical_Offline(dl->physical);	/* Is this required ? */
34014e34a55SBrian Somers           if (dl->script.run) {
34114e34a55SBrian Somers             datalink_NewState(dl, DATALINK_HANGUP);
342c39aa54eSBrian Somers             if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
343c39aa54eSBrian Somers               log_Printf(LogWARN, "Invalid hangup script\n");
344eb6e5e05SBrian Somers             return datalink_UpdateSet(d, r, w, e, n);
345da8b7034SBrian Somers           } else {
346da8b7034SBrian Somers             datalink_HangupDone(dl);
347da8b7034SBrian Somers             return 0;	/* Maybe bundle_CleanDatalinks() has something to do */
348da8b7034SBrian Somers           }
349eb6e5e05SBrian Somers       }
350eb6e5e05SBrian Somers 
3513006ec67SBrian Somers     case DATALINK_HANGUP:
3523006ec67SBrian Somers     case DATALINK_DIAL:
353c116e0c0SBrian Somers     case DATALINK_LOGOUT:
3543006ec67SBrian Somers     case DATALINK_LOGIN:
3553006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
3563006ec67SBrian Somers       switch (dl->chat.state) {
3573006ec67SBrian Somers         case CHAT_DONE:
3583006ec67SBrian Somers           /* script succeeded */
3593006ec67SBrian Somers           switch(dl->state) {
3603006ec67SBrian Somers             case DATALINK_HANGUP:
3613006ec67SBrian Somers               datalink_HangupDone(dl);
3623006ec67SBrian Somers               break;
3633006ec67SBrian Somers             case DATALINK_DIAL:
364eb6e5e05SBrian Somers               datalink_NewState(dl, DATALINK_CARRIER);
3651342caedSBrian Somers               return datalink_UpdateSet(d, r, w, e, n);
366c116e0c0SBrian Somers             case DATALINK_LOGOUT:
367c116e0c0SBrian Somers               datalink_NewState(dl, DATALINK_HANGUP);
368c116e0c0SBrian Somers               physical_Offline(dl->physical);
369c39aa54eSBrian Somers               if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
370c39aa54eSBrian Somers                 log_Printf(LogWARN, "Invalid hangup script\n");
371c116e0c0SBrian Somers               return datalink_UpdateSet(d, r, w, e, n);
3723006ec67SBrian Somers             case DATALINK_LOGIN:
37347dd77c1SBrian Somers               dl->phone.alt = NULL;
374c5a5a6caSBrian Somers               datalink_LoginDone(dl);
375b51a60ccSBrian Somers               return datalink_UpdateSet(d, r, w, e, n);
3763006ec67SBrian Somers           }
3773006ec67SBrian Somers           break;
3783006ec67SBrian Somers         case CHAT_FAILED:
3793006ec67SBrian Somers           /* Going down - script failed */
380dd7e2610SBrian Somers           log_Printf(LogWARN, "Chat script failed\n");
3813006ec67SBrian Somers           switch(dl->state) {
3823006ec67SBrian Somers             case DATALINK_HANGUP:
3833006ec67SBrian Somers               datalink_HangupDone(dl);
3843006ec67SBrian Somers               break;
3853006ec67SBrian Somers             case DATALINK_DIAL:
386c116e0c0SBrian Somers             case DATALINK_LOGOUT:
3873006ec67SBrian Somers             case DATALINK_LOGIN:
3889ae58882SBrian Somers               datalink_NewState(dl, DATALINK_HANGUP);
389c116e0c0SBrian Somers               physical_Offline(dl->physical);
390c39aa54eSBrian Somers               if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
391c39aa54eSBrian Somers                 log_Printf(LogWARN, "Invalid hangup script\n");
3921342caedSBrian Somers               return datalink_UpdateSet(d, r, w, e, n);
3933006ec67SBrian Somers           }
3943006ec67SBrian Somers           break;
3953006ec67SBrian Somers       }
3963006ec67SBrian Somers       break;
397c7cc5030SBrian Somers 
398c7cc5030SBrian Somers     case DATALINK_READY:
399e2ebb036SBrian Somers     case DATALINK_LCP:
400e2ebb036SBrian Somers     case DATALINK_AUTH:
40192b09558SBrian Somers     case DATALINK_CBCP:
4023006ec67SBrian Somers     case DATALINK_OPEN:
40358330d7bSBrian Somers       result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) +
40458330d7bSBrian Somers                descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
4053006ec67SBrian Somers       break;
4063006ec67SBrian Somers   }
4073006ec67SBrian Somers   return result;
4083006ec67SBrian Somers }
4093006ec67SBrian Somers 
410ea722969SBrian Somers int
411ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e)
412ea722969SBrian Somers {
413ea722969SBrian Somers   return physical_RemoveFromSet(dl->physical, r, w, e);
414ea722969SBrian Somers }
415ea722969SBrian Somers 
4163006ec67SBrian Somers static int
417f013f33eSBrian Somers datalink_IsSet(struct fdescriptor *d, const fd_set *fdset)
4183006ec67SBrian Somers {
4193006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
4203006ec67SBrian Somers 
4213006ec67SBrian Somers   switch (dl->state) {
4223006ec67SBrian Somers     case DATALINK_CLOSED:
423c7cc5030SBrian Somers     case DATALINK_OPENING:
4243006ec67SBrian Somers       break;
425c7cc5030SBrian Somers 
4263006ec67SBrian Somers     case DATALINK_HANGUP:
4273006ec67SBrian Somers     case DATALINK_DIAL:
428c116e0c0SBrian Somers     case DATALINK_LOGOUT:
4293006ec67SBrian Somers     case DATALINK_LOGIN:
4303006ec67SBrian Somers       return descriptor_IsSet(&dl->chat.desc, fdset);
431c7cc5030SBrian Somers 
432c7cc5030SBrian Somers     case DATALINK_READY:
433e2ebb036SBrian Somers     case DATALINK_LCP:
434e2ebb036SBrian Somers     case DATALINK_AUTH:
43592b09558SBrian Somers     case DATALINK_CBCP:
4363006ec67SBrian Somers     case DATALINK_OPEN:
43758330d7bSBrian Somers       return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 :
43858330d7bSBrian Somers              descriptor_IsSet(&dl->physical->desc, fdset);
4393006ec67SBrian Somers   }
4403006ec67SBrian Somers   return 0;
4413006ec67SBrian Somers }
4423006ec67SBrian Somers 
4433006ec67SBrian Somers static void
444f013f33eSBrian Somers datalink_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
4453006ec67SBrian Somers {
4463006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
4473006ec67SBrian Somers 
4483006ec67SBrian Somers   switch (dl->state) {
4493006ec67SBrian Somers     case DATALINK_CLOSED:
450c7cc5030SBrian Somers     case DATALINK_OPENING:
4513006ec67SBrian Somers       break;
452c7cc5030SBrian Somers 
4533006ec67SBrian Somers     case DATALINK_HANGUP:
4543006ec67SBrian Somers     case DATALINK_DIAL:
455c116e0c0SBrian Somers     case DATALINK_LOGOUT:
4563006ec67SBrian Somers     case DATALINK_LOGIN:
4573006ec67SBrian Somers       descriptor_Read(&dl->chat.desc, bundle, fdset);
4583006ec67SBrian Somers       break;
459c7cc5030SBrian Somers 
460c7cc5030SBrian Somers     case DATALINK_READY:
461e2ebb036SBrian Somers     case DATALINK_LCP:
462e2ebb036SBrian Somers     case DATALINK_AUTH:
46392b09558SBrian Somers     case DATALINK_CBCP:
4643006ec67SBrian Somers     case DATALINK_OPEN:
46558330d7bSBrian Somers       if (descriptor_IsSet(&dl->chap.desc, fdset))
46658330d7bSBrian Somers         descriptor_Read(&dl->chap.desc, bundle, fdset);
46758330d7bSBrian Somers       if (descriptor_IsSet(&dl->physical->desc, fdset))
4683006ec67SBrian Somers         descriptor_Read(&dl->physical->desc, bundle, fdset);
4693006ec67SBrian Somers       break;
4703006ec67SBrian Somers   }
4713006ec67SBrian Somers }
4723006ec67SBrian Somers 
4731af29a6eSBrian Somers static int
4749b996792SBrian Somers datalink_Write(struct fdescriptor *d, struct bundle *bundle,
4759b996792SBrian Somers                const fd_set *fdset)
4763006ec67SBrian Somers {
4773006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
4781af29a6eSBrian Somers   int result = 0;
4793006ec67SBrian Somers 
4803006ec67SBrian Somers   switch (dl->state) {
4813006ec67SBrian Somers     case DATALINK_CLOSED:
482c7cc5030SBrian Somers     case DATALINK_OPENING:
4833006ec67SBrian Somers       break;
484c7cc5030SBrian Somers 
4853006ec67SBrian Somers     case DATALINK_HANGUP:
4863006ec67SBrian Somers     case DATALINK_DIAL:
487c116e0c0SBrian Somers     case DATALINK_LOGOUT:
4883006ec67SBrian Somers     case DATALINK_LOGIN:
4891af29a6eSBrian Somers       result = descriptor_Write(&dl->chat.desc, bundle, fdset);
4903006ec67SBrian Somers       break;
491c7cc5030SBrian Somers 
492c7cc5030SBrian Somers     case DATALINK_READY:
493e2ebb036SBrian Somers     case DATALINK_LCP:
494e2ebb036SBrian Somers     case DATALINK_AUTH:
49592b09558SBrian Somers     case DATALINK_CBCP:
4963006ec67SBrian Somers     case DATALINK_OPEN:
49758330d7bSBrian Somers       if (descriptor_IsSet(&dl->chap.desc, fdset))
49858330d7bSBrian Somers         result += descriptor_Write(&dl->chap.desc, bundle, fdset);
49958330d7bSBrian Somers       if (descriptor_IsSet(&dl->physical->desc, fdset))
50058330d7bSBrian Somers         result += descriptor_Write(&dl->physical->desc, bundle, fdset);
5013006ec67SBrian Somers       break;
5023006ec67SBrian Somers   }
5031af29a6eSBrian Somers 
5041af29a6eSBrian Somers   return result;
5053006ec67SBrian Somers }
5063006ec67SBrian Somers 
5076d666775SBrian Somers static void
5089c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how)
509e2ebb036SBrian Somers {
5102fc2f705SBrian Somers   int stayonline;
511e2ebb036SBrian Somers 
5122fc2f705SBrian Somers   if (how == CLOSE_LCP)
5132fc2f705SBrian Somers     datalink_DontHangup(dl);
5142fc2f705SBrian Somers   else if (how == CLOSE_STAYDOWN)
5152fc2f705SBrian Somers     datalink_StayDown(dl);
5162fc2f705SBrian Somers 
5172fc2f705SBrian Somers   stayonline = dl->stayonline;
5189c81b87dSBrian Somers   dl->stayonline = 0;
5192fc2f705SBrian Somers 
5202fc2f705SBrian Somers   if (dl->state >= DATALINK_READY && stayonline) {
5216815097bSBrian Somers     physical_StopDeviceTimer(dl->physical);
5229c81b87dSBrian Somers     datalink_NewState(dl, DATALINK_READY);
5239c81b87dSBrian Somers   } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
5245d9e6103SBrian Somers     physical_Offline(dl->physical);
525e2ebb036SBrian Somers     if (dl->script.run && dl->state != DATALINK_OPENING) {
526c116e0c0SBrian Somers       if (dl->state == DATALINK_LOGOUT) {
5279ae58882SBrian Somers         datalink_NewState(dl, DATALINK_HANGUP);
528c39aa54eSBrian Somers         if (!chat_Setup(&dl->chat, dl->cfg.script.hangup, NULL))
529c39aa54eSBrian Somers           log_Printf(LogWARN, "Invalid hangup script\n");
530c116e0c0SBrian Somers       } else {
531c116e0c0SBrian Somers         datalink_NewState(dl, DATALINK_LOGOUT);
532c39aa54eSBrian Somers         if (!chat_Setup(&dl->chat, dl->cfg.script.logout, NULL))
533c39aa54eSBrian Somers           log_Printf(LogWARN, "Invalid logout script\n");
534c116e0c0SBrian Somers       }
535e2ebb036SBrian Somers     } else
536e2ebb036SBrian Somers       datalink_HangupDone(dl);
537e2ebb036SBrian Somers   }
538e2ebb036SBrian Somers }
539e2ebb036SBrian Somers 
540e2ebb036SBrian Somers static void
5416d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp)
5426d666775SBrian Somers {
5436d666775SBrian Somers   /* The given FSM is about to start up ! */
5446d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
545a611cad6SBrian Somers 
54692e872e7SBrian Somers   if (fp->proto == PROTO_LCP)
547e2ebb036SBrian Somers     (*dl->parent->LayerStart)(dl->parent->object, fp);
548e2ebb036SBrian Somers }
5496d666775SBrian Somers 
5506d666775SBrian Somers static void
5516d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp)
5526d666775SBrian Somers {
5536d666775SBrian Somers   /* The given fsm is now up */
5546d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
5555e315498SBrian Somers   struct lcp *lcp = &dl->physical->link.lcp;
5566d666775SBrian Somers 
55792e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
558f0cdd9c0SBrian Somers     datalink_GotAuthname(dl, "");
5595e315498SBrian Somers     lcp->auth_ineed = lcp->want_auth;
5605e315498SBrian Somers     lcp->auth_iwait = lcp->his_auth;
5615e315498SBrian Somers     if (lcp->his_auth || lcp->want_auth) {
5625945a079SBrian Somers       if (bundle_Phase(dl->bundle) != PHASE_NETWORK)
5635563ebdeSBrian Somers         bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
564dd7e2610SBrian Somers       log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
5655e315498SBrian Somers                 Auth2Nam(lcp->his_auth, lcp->his_authtype),
5665e315498SBrian Somers                 Auth2Nam(lcp->want_auth, lcp->want_authtype));
5675e315498SBrian Somers       if (lcp->his_auth == PROTO_PAP)
568f0cdd9c0SBrian Somers         auth_StartReq(&dl->pap);
5695e315498SBrian Somers       if (lcp->want_auth == PROTO_CHAP)
570f0cdd9c0SBrian Somers         auth_StartReq(&dl->chap.auth);
571e2ebb036SBrian Somers     } else
572e2ebb036SBrian Somers       datalink_AuthOk(dl);
573e2ebb036SBrian Somers   }
574e2ebb036SBrian Somers }
575e2ebb036SBrian Somers 
57664cfdfc6SBrian Somers static void
57764cfdfc6SBrian Somers datalink_AuthReInit(struct datalink *dl)
57864cfdfc6SBrian Somers {
57964cfdfc6SBrian Somers   auth_StopTimer(&dl->pap);
58064cfdfc6SBrian Somers   auth_StopTimer(&dl->chap.auth);
58164cfdfc6SBrian Somers   chap_ReInit(&dl->chap);
58264cfdfc6SBrian Somers }
58364cfdfc6SBrian Somers 
584e2ebb036SBrian Somers void
585f0cdd9c0SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name)
586643f4904SBrian Somers {
587f0cdd9c0SBrian Somers   strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1);
588f0cdd9c0SBrian Somers   dl->peer.authname[sizeof dl->peer.authname - 1] = '\0';
589643f4904SBrian Somers }
590643f4904SBrian Somers 
591643f4904SBrian Somers void
59292b09558SBrian Somers datalink_NCPUp(struct datalink *dl)
593e2ebb036SBrian Somers {
59406337856SBrian Somers   int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp);
5951df0a3b9SBrian Somers 
596dbf60d74SBrian Somers   if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) {
5971fa665f5SBrian Somers     /* we've authenticated in multilink mode ! */
5981fa665f5SBrian Somers     switch (mp_Up(&dl->bundle->ncp.mp, dl)) {
5991fa665f5SBrian Somers       case MP_LINKSENT:
600ea722969SBrian Somers         /* We've handed the link off to another ppp (well, we will soon) ! */
6011fa665f5SBrian Somers         return;
6021fa665f5SBrian Somers       case MP_UP:
6030a1b5c9dSBrian Somers         /* First link in the bundle */
60492b09558SBrian Somers         auth_Select(dl->bundle, dl->peer.authname);
605ab2de065SBrian Somers         bundle_CalculateBandwidth(dl->bundle);
6060a1b5c9dSBrian Somers         /* fall through */
6071fa665f5SBrian Somers       case MP_ADDED:
6080a1b5c9dSBrian Somers         /* We're in multilink mode ! */
6091df0a3b9SBrian Somers         dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE;	/* override */
610ab2de065SBrian Somers         bundle_CalculateBandwidth(dl->bundle);
6111fa665f5SBrian Somers         break;
6121fa665f5SBrian Somers       case MP_FAILED:
61349052c95SBrian Somers         datalink_AuthNotOk(dl);
61449052c95SBrian Somers         return;
61549052c95SBrian Somers     }
61649052c95SBrian Somers   } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) {
617dd7e2610SBrian Somers     log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name);
618897f9429SBrian Somers     datalink_NewState(dl, DATALINK_OPEN);
619ab2de065SBrian Somers     bundle_CalculateBandwidth(dl->bundle);
620897f9429SBrian Somers     (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
62149052c95SBrian Somers     return;
62250abd4c8SBrian Somers   } else {
62350abd4c8SBrian Somers     dl->bundle->ncp.mp.peer = dl->peer;
624ce828a6eSBrian Somers     ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link);
62592b09558SBrian Somers     auth_Select(dl->bundle, dl->peer.authname);
62650abd4c8SBrian Somers   }
62749052c95SBrian Somers 
62806337856SBrian Somers   if (ccpok) {
629dd7e2610SBrian Somers     fsm_Up(&dl->physical->link.ccp.fsm);
630dd7e2610SBrian Somers     fsm_Open(&dl->physical->link.ccp.fsm);
63106337856SBrian Somers   }
6329ae58882SBrian Somers   datalink_NewState(dl, DATALINK_OPEN);
6333b0f8d2eSBrian Somers   bundle_NewPhase(dl->bundle, PHASE_NETWORK);
6343b0f8d2eSBrian Somers   (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
6356d666775SBrian Somers }
636e2ebb036SBrian Somers 
637e2ebb036SBrian Somers void
63892b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl)
63992b09558SBrian Somers {
64092b09558SBrian Somers   datalink_NewState(dl, DATALINK_LCP);
64164cfdfc6SBrian Somers   datalink_AuthReInit(dl);
64292b09558SBrian Somers   fsm_Close(&dl->physical->link.lcp.fsm);
64392b09558SBrian Somers }
64492b09558SBrian Somers 
64592b09558SBrian Somers void
64692b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl)
64792b09558SBrian Somers {
64892b09558SBrian Somers   cbcp_Down(&dl->cbcp);
64992b09558SBrian Somers   datalink_CBCPComplete(dl);
65092b09558SBrian Somers }
65192b09558SBrian Somers 
65292b09558SBrian Somers void
65392b09558SBrian Somers datalink_AuthOk(struct datalink *dl)
65492b09558SBrian Somers {
6555165af6fSBrian Somers   if ((dl->physical->link.lcp.his_callback.opmask &
65692b09558SBrian Somers        CALLBACK_BIT(CALLBACK_CBCP) ||
6575165af6fSBrian Somers        dl->physical->link.lcp.want_callback.opmask &
6585165af6fSBrian Somers        CALLBACK_BIT(CALLBACK_CBCP)) &&
6595165af6fSBrian Somers       !(dl->physical->link.lcp.want_callback.opmask &
6605165af6fSBrian Somers         CALLBACK_BIT(CALLBACK_AUTH))) {
6615165af6fSBrian Somers     /* We must have agreed CBCP if AUTH isn't there any more */
66292b09558SBrian Somers     datalink_NewState(dl, DATALINK_CBCP);
66392b09558SBrian Somers     cbcp_Up(&dl->cbcp);
66492b09558SBrian Somers   } else if (dl->physical->link.lcp.want_callback.opmask) {
6655165af6fSBrian Somers     /* It's not CBCP */
66692b09558SBrian Somers     log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name);
66792b09558SBrian Somers     datalink_NewState(dl, DATALINK_LCP);
66864cfdfc6SBrian Somers     datalink_AuthReInit(dl);
66992b09558SBrian Somers     fsm_Close(&dl->physical->link.lcp.fsm);
67092b09558SBrian Somers   } else
67192b09558SBrian Somers     switch (dl->physical->link.lcp.his_callback.opmask) {
67292b09558SBrian Somers       case 0:
67392b09558SBrian Somers         datalink_NCPUp(dl);
67492b09558SBrian Somers         break;
67592b09558SBrian Somers 
67692b09558SBrian Somers       case CALLBACK_BIT(CALLBACK_AUTH):
67792b09558SBrian Somers         auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone,
67892b09558SBrian Somers                           sizeof dl->cbcp.fsm.phone);
67992b09558SBrian Somers         if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) {
68092b09558SBrian Somers           log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name,
68192b09558SBrian Somers                      dl->peer.authname);
68292b09558SBrian Somers           *dl->cbcp.fsm.phone = '\0';
68392b09558SBrian Somers         } else {
68492b09558SBrian Somers           char *ptr = strchr(dl->cbcp.fsm.phone, ',');
68592b09558SBrian Somers           if (ptr)
68692b09558SBrian Somers             *ptr = '\0';	/* Call back on the first number */
68792b09558SBrian Somers           log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
68892b09558SBrian Somers                      dl->cbcp.fsm.phone);
68992b09558SBrian Somers           dl->cbcp.required = 1;
69092b09558SBrian Somers         }
69192b09558SBrian Somers         dl->cbcp.fsm.delay = 0;
69292b09558SBrian Somers         datalink_NewState(dl, DATALINK_LCP);
69364cfdfc6SBrian Somers         datalink_AuthReInit(dl);
69492b09558SBrian Somers         fsm_Close(&dl->physical->link.lcp.fsm);
69592b09558SBrian Somers         break;
69692b09558SBrian Somers 
69792b09558SBrian Somers       case CALLBACK_BIT(CALLBACK_E164):
69892b09558SBrian Somers         strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg,
69992b09558SBrian Somers                 sizeof dl->cbcp.fsm.phone - 1);
70092b09558SBrian Somers         dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0';
70192b09558SBrian Somers         log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
70292b09558SBrian Somers                    dl->cbcp.fsm.phone);
70392b09558SBrian Somers         dl->cbcp.required = 1;
70492b09558SBrian Somers         dl->cbcp.fsm.delay = 0;
70592b09558SBrian Somers         datalink_NewState(dl, DATALINK_LCP);
70664cfdfc6SBrian Somers         datalink_AuthReInit(dl);
70792b09558SBrian Somers         fsm_Close(&dl->physical->link.lcp.fsm);
70892b09558SBrian Somers         break;
70992b09558SBrian Somers 
71092b09558SBrian Somers       default:
71192b09558SBrian Somers         log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n",
71292b09558SBrian Somers                    dl->name);
71392b09558SBrian Somers         datalink_NewState(dl, DATALINK_LCP);
71464cfdfc6SBrian Somers         datalink_AuthReInit(dl);
71592b09558SBrian Somers         fsm_Close(&dl->physical->link.lcp.fsm);
71692b09558SBrian Somers         break;
71792b09558SBrian Somers     }
71892b09558SBrian Somers }
71992b09558SBrian Somers 
72092b09558SBrian Somers void
721e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl)
722e2ebb036SBrian Somers {
7239ae58882SBrian Somers   datalink_NewState(dl, DATALINK_LCP);
72464cfdfc6SBrian Somers   datalink_AuthReInit(dl);
725dd7e2610SBrian Somers   fsm_Close(&dl->physical->link.lcp.fsm);
7266d666775SBrian Somers }
7276d666775SBrian Somers 
7286d666775SBrian Somers static void
7296d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp)
7306d666775SBrian Somers {
7316d666775SBrian Somers   /* The given FSM has been told to come down */
7326d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
733a611cad6SBrian Somers 
73492e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
735e2ebb036SBrian Somers     switch (dl->state) {
736e2ebb036SBrian Somers       case DATALINK_OPEN:
737643f4904SBrian Somers         peerid_Init(&dl->peer);
73809206a6fSBrian Somers         fsm2initial(&dl->physical->link.ccp.fsm);
739ff0f9439SBrian Somers         datalink_NewState(dl, DATALINK_LCP);  /* before parent TLD */
740e2ebb036SBrian Somers         (*dl->parent->LayerDown)(dl->parent->object, fp);
74192b09558SBrian Somers         /* fall through (just in case) */
74292b09558SBrian Somers 
74392b09558SBrian Somers       case DATALINK_CBCP:
74492b09558SBrian Somers         if (!dl->cbcp.required)
74592b09558SBrian Somers           cbcp_Down(&dl->cbcp);
74692b09558SBrian Somers         /* fall through (just in case) */
747e2ebb036SBrian Somers 
748e2ebb036SBrian Somers       case DATALINK_AUTH:
749dd7e2610SBrian Somers         timer_Stop(&dl->pap.authtimer);
750dd7e2610SBrian Somers         timer_Stop(&dl->chap.auth.authtimer);
7516d666775SBrian Somers     }
7529ae58882SBrian Somers     datalink_NewState(dl, DATALINK_LCP);
75364cfdfc6SBrian Somers     datalink_AuthReInit(dl);
754e2ebb036SBrian Somers   }
7556d666775SBrian Somers }
7566d666775SBrian Somers 
7576d666775SBrian Somers static void
7586d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp)
7596d666775SBrian Somers {
7606d666775SBrian Somers   /* The given fsm is now down */
7616d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
7626d666775SBrian Somers 
76392e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
76409206a6fSBrian Somers     fsm2initial(fp);
7656d666775SBrian Somers     (*dl->parent->LayerFinish)(dl->parent->object, fp);
7669c81b87dSBrian Somers     datalink_ComeDown(dl, CLOSE_NORMAL);
7670a1b5c9dSBrian Somers   } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE)
7680a1b5c9dSBrian Somers     fsm_Open(fp);		/* CCP goes to ST_STOPPED */
7696d666775SBrian Somers }
7706d666775SBrian Somers 
7713006ec67SBrian Somers struct datalink *
7726f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type)
7733006ec67SBrian Somers {
7743006ec67SBrian Somers   struct datalink *dl;
7753006ec67SBrian Somers 
7763006ec67SBrian Somers   dl = (struct datalink *)malloc(sizeof(struct datalink));
7773006ec67SBrian Somers   if (dl == NULL)
7783006ec67SBrian Somers     return dl;
7793006ec67SBrian Somers 
7803006ec67SBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
7813006ec67SBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
7823006ec67SBrian Somers   dl->desc.IsSet = datalink_IsSet;
7833006ec67SBrian Somers   dl->desc.Read = datalink_Read;
7843006ec67SBrian Somers   dl->desc.Write = datalink_Write;
7855b8b8060SBrian Somers 
786e718d1d7SBrian Somers   dl->state = DATALINK_CLOSED;
787e718d1d7SBrian Somers 
78873a13b5cSBrian Somers   *dl->cfg.script.dial = '\0';
78973a13b5cSBrian Somers   *dl->cfg.script.login = '\0';
790c116e0c0SBrian Somers   *dl->cfg.script.logout = '\0';
79173a13b5cSBrian Somers   *dl->cfg.script.hangup = '\0';
792f9545805SBrian Somers   *dl->cfg.phone.list = '\0';
793f9545805SBrian Somers   *dl->phone.list = '\0';
794f9545805SBrian Somers   dl->phone.next = NULL;
795f9545805SBrian Somers   dl->phone.alt = NULL;
796f9545805SBrian Somers   dl->phone.chosen = "N/A";
7979c81b87dSBrian Somers   dl->stayonline = 0;
798c7cc5030SBrian Somers   dl->script.run = 1;
799c7cc5030SBrian Somers   dl->script.packetmode = 1;
8003b0f8d2eSBrian Somers   mp_linkInit(&dl->mp);
8015b8b8060SBrian Somers 
8023006ec67SBrian Somers   dl->bundle = bundle;
8033006ec67SBrian Somers   dl->next = NULL;
804e718d1d7SBrian Somers 
805c11e57a3SBrian Somers   memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
806e718d1d7SBrian Somers 
807c11e57a3SBrian Somers   dl->dial.tries = 0;
808565e35e5SBrian Somers   dl->cfg.dial.max = 1;
809565e35e5SBrian Somers   dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
810565e35e5SBrian Somers   dl->cfg.dial.timeout = DIAL_TIMEOUT;
811c11e57a3SBrian Somers   dl->cfg.dial.inc = 0;
812c11e57a3SBrian Somers   dl->cfg.dial.maxinc = 10;
813e718d1d7SBrian Somers 
814abff9baeSBrian Somers   dl->reconnect_tries = 0;
815565e35e5SBrian Somers   dl->cfg.reconnect.max = 0;
816565e35e5SBrian Somers   dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
817abff9baeSBrian Somers 
81892b09558SBrian Somers   dl->cfg.callback.opmask = 0;
81992b09558SBrian Somers   dl->cfg.cbcp.delay = 0;
82092b09558SBrian Somers   *dl->cfg.cbcp.phone = '\0';
82192b09558SBrian Somers   dl->cfg.cbcp.fsmretry = DEF_FSMRETRY;
82292b09558SBrian Somers 
8233006ec67SBrian Somers   dl->name = strdup(name);
824643f4904SBrian Somers   peerid_Init(&dl->peer);
8256f384573SBrian Somers   dl->parent = &bundle->fsm;
8263b0f8d2eSBrian Somers   dl->fsmp.LayerStart = datalink_LayerStart;
8273b0f8d2eSBrian Somers   dl->fsmp.LayerUp = datalink_LayerUp;
8283b0f8d2eSBrian Somers   dl->fsmp.LayerDown = datalink_LayerDown;
8293b0f8d2eSBrian Somers   dl->fsmp.LayerFinish = datalink_LayerFinish;
8303b0f8d2eSBrian Somers   dl->fsmp.object = dl;
8313b0f8d2eSBrian Somers 
8325d9e6103SBrian Somers   if ((dl->physical = physical_Create(dl, type)) == NULL) {
8333006ec67SBrian Somers     free(dl->name);
8343006ec67SBrian Somers     free(dl);
8353006ec67SBrian Somers     return NULL;
8363006ec67SBrian Somers   }
837f0cdd9c0SBrian Somers 
838f0cdd9c0SBrian Somers   pap_Init(&dl->pap, dl->physical);
839f0cdd9c0SBrian Somers   chap_Init(&dl->chap, dl->physical);
84092b09558SBrian Somers   cbcp_Init(&dl->cbcp, dl->physical);
841c116e0c0SBrian Somers 
842c116e0c0SBrian Somers   memset(&dl->chat, '\0', sizeof dl->chat);	/* Force buf{start,end} reset */
843ffcfaec7SBrian Somers   chat_Init(&dl->chat, dl->physical);
8443006ec67SBrian Somers 
8459ae58882SBrian Somers   log_Printf(LogPHASE, "%s: Created in %s state\n",
8469ae58882SBrian Somers              dl->name, datalink_State(dl));
8473006ec67SBrian Somers 
8483006ec67SBrian Somers   return dl;
8493006ec67SBrian Somers }
8503006ec67SBrian Somers 
8513006ec67SBrian Somers struct datalink *
852cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name)
853cd7bd93aSBrian Somers {
854cd7bd93aSBrian Somers   struct datalink *dl;
855cd7bd93aSBrian Somers 
856cd7bd93aSBrian Somers   dl = (struct datalink *)malloc(sizeof(struct datalink));
857cd7bd93aSBrian Somers   if (dl == NULL)
858cd7bd93aSBrian Somers     return dl;
859cd7bd93aSBrian Somers 
860cd7bd93aSBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
861cd7bd93aSBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
862cd7bd93aSBrian Somers   dl->desc.IsSet = datalink_IsSet;
863cd7bd93aSBrian Somers   dl->desc.Read = datalink_Read;
864cd7bd93aSBrian Somers   dl->desc.Write = datalink_Write;
865cd7bd93aSBrian Somers 
866cd7bd93aSBrian Somers   dl->state = DATALINK_CLOSED;
867cd7bd93aSBrian Somers 
868cd7bd93aSBrian Somers   memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
869cd7bd93aSBrian Somers   mp_linkInit(&dl->mp);
870cd7bd93aSBrian Somers   *dl->phone.list = '\0';
871643f4904SBrian Somers   dl->phone.next = NULL;
872643f4904SBrian Somers   dl->phone.alt = NULL;
873643f4904SBrian Somers   dl->phone.chosen = "N/A";
874cd7bd93aSBrian Somers   dl->bundle = odl->bundle;
875cd7bd93aSBrian Somers   dl->next = NULL;
876c11e57a3SBrian Somers   memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
877c11e57a3SBrian Somers   dl->dial.tries = 0;
878cd7bd93aSBrian Somers   dl->reconnect_tries = 0;
879cd7bd93aSBrian Somers   dl->name = strdup(name);
880643f4904SBrian Somers   peerid_Init(&dl->peer);
881cd7bd93aSBrian Somers   dl->parent = odl->parent;
882cd7bd93aSBrian Somers   memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
883643f4904SBrian Somers   dl->fsmp.object = dl;
884cd7bd93aSBrian Somers 
8855d9e6103SBrian Somers   if ((dl->physical = physical_Create(dl, PHYS_INTERACTIVE)) == NULL) {
886cd7bd93aSBrian Somers     free(dl->name);
887cd7bd93aSBrian Somers     free(dl);
888cd7bd93aSBrian Somers     return NULL;
889cd7bd93aSBrian Somers   }
890f0cdd9c0SBrian Somers   pap_Init(&dl->pap, dl->physical);
891479508cfSBrian Somers   dl->pap.cfg = odl->pap.cfg;
892f0cdd9c0SBrian Somers 
893f0cdd9c0SBrian Somers   chap_Init(&dl->chap, dl->physical);
894479508cfSBrian Somers   dl->chap.auth.cfg = odl->chap.auth.cfg;
895f0cdd9c0SBrian Somers 
896cd7bd93aSBrian Somers   memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
897cd7bd93aSBrian Somers   memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
898cd7bd93aSBrian Somers          sizeof dl->physical->link.lcp.cfg);
899cd7bd93aSBrian Somers   memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
900cd7bd93aSBrian Somers          sizeof dl->physical->link.ccp.cfg);
901cd7bd93aSBrian Somers   memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
902cd7bd93aSBrian Somers          sizeof dl->physical->async.cfg);
903cd7bd93aSBrian Somers 
90492b09558SBrian Somers   cbcp_Init(&dl->cbcp, dl->physical);
905c116e0c0SBrian Somers 
906c116e0c0SBrian Somers   memset(&dl->chat, '\0', sizeof dl->chat);	/* Force buf{start,end} reset */
907ffcfaec7SBrian Somers   chat_Init(&dl->chat, dl->physical);
908cd7bd93aSBrian Somers 
9099ae58882SBrian Somers   log_Printf(LogPHASE, "%s: Cloned in %s state\n",
9109ae58882SBrian Somers              dl->name, datalink_State(dl));
911cd7bd93aSBrian Somers 
912cd7bd93aSBrian Somers   return dl;
913cd7bd93aSBrian Somers }
914cd7bd93aSBrian Somers 
915cd7bd93aSBrian Somers struct datalink *
9163006ec67SBrian Somers datalink_Destroy(struct datalink *dl)
9173006ec67SBrian Somers {
9183006ec67SBrian Somers   struct datalink *result;
9193006ec67SBrian Somers 
92039d94652SBrian Somers   if (dl->state != DATALINK_CLOSED) {
921dd7e2610SBrian Somers     log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n",
922c7cc5030SBrian Somers               datalink_State(dl));
92339d94652SBrian Somers     switch (dl->state) {
92439d94652SBrian Somers       case DATALINK_HANGUP:
92539d94652SBrian Somers       case DATALINK_DIAL:
92639d94652SBrian Somers       case DATALINK_LOGIN:
927ffcfaec7SBrian Somers         chat_Finish(&dl->chat);		/* Gotta blat the timers ! */
92839d94652SBrian Somers         break;
92939d94652SBrian Somers     }
93039d94652SBrian Somers   }
9313006ec67SBrian Somers 
932ffcfaec7SBrian Somers   chat_Destroy(&dl->chat);
933c11e57a3SBrian Somers   timer_Stop(&dl->dial.timer);
9343006ec67SBrian Somers   result = dl->next;
9355d9e6103SBrian Somers   physical_Destroy(dl->physical);
9363006ec67SBrian Somers   free(dl->name);
9373006ec67SBrian Somers   free(dl);
9383006ec67SBrian Somers 
9393006ec67SBrian Somers   return result;
9403006ec67SBrian Somers }
9413006ec67SBrian Somers 
9423006ec67SBrian Somers void
943c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode)
9443006ec67SBrian Somers {
9456f384573SBrian Somers   if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
946565e35e5SBrian Somers     /* Ignore scripts */
947565e35e5SBrian Somers     runscripts = 0;
948565e35e5SBrian Somers 
949c7cc5030SBrian Somers   switch (dl->state) {
950c7cc5030SBrian Somers     case DATALINK_CLOSED:
9513b0f8d2eSBrian Somers       if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
9523b0f8d2eSBrian Somers           bundle_Phase(dl->bundle) == PHASE_TERMINATE)
9533b0f8d2eSBrian Somers         bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
9549ae58882SBrian Somers       datalink_NewState(dl, DATALINK_OPENING);
955565e35e5SBrian Somers       dl->reconnect_tries =
9566f384573SBrian Somers         dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max;
957c11e57a3SBrian Somers       dl->dial.tries = dl->cfg.dial.max;
958c5a5a6caSBrian Somers       dl->script.run = runscripts;
959c5a5a6caSBrian Somers       dl->script.packetmode = packetmode;
960c7cc5030SBrian Somers       break;
961c7cc5030SBrian Somers 
962c7cc5030SBrian Somers     case DATALINK_OPENING:
963c7cc5030SBrian Somers       if (!dl->script.run && runscripts)
964c7cc5030SBrian Somers         dl->script.run = 1;
965c7cc5030SBrian Somers       /* fall through */
966c7cc5030SBrian Somers 
967c7cc5030SBrian Somers     case DATALINK_DIAL:
968c7cc5030SBrian Somers     case DATALINK_LOGIN:
969c7cc5030SBrian Somers     case DATALINK_READY:
970c7cc5030SBrian Somers       if (!dl->script.packetmode && packetmode) {
971c7cc5030SBrian Somers         dl->script.packetmode = 1;
9725e269efeSBrian Somers         if (dl->state == DATALINK_READY) {
9735e269efeSBrian Somers           dl->script.run = 0;
9745e269efeSBrian Somers           datalink_NewState(dl, DATALINK_CARRIER);
9755e269efeSBrian Somers         }
976c7cc5030SBrian Somers       }
977c7cc5030SBrian Somers       break;
9783006ec67SBrian Somers   }
9793006ec67SBrian Somers }
9803006ec67SBrian Somers 
9813006ec67SBrian Somers void
9829c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how)
983c7cc5030SBrian Somers {
984c7cc5030SBrian Somers   /* Please close */
985e2ebb036SBrian Somers   switch (dl->state) {
986e2ebb036SBrian Somers     case DATALINK_OPEN:
987643f4904SBrian Somers       peerid_Init(&dl->peer);
98809206a6fSBrian Somers       fsm2initial(&dl->physical->link.ccp.fsm);
989e2ebb036SBrian Somers       /* fall through */
990e2ebb036SBrian Somers 
99192b09558SBrian Somers     case DATALINK_CBCP:
992e2ebb036SBrian Somers     case DATALINK_AUTH:
993e2ebb036SBrian Somers     case DATALINK_LCP:
99464cfdfc6SBrian Somers       datalink_AuthReInit(dl);
9959c81b87dSBrian Somers       if (how == CLOSE_LCP)
9962fc2f705SBrian Somers         datalink_DontHangup(dl);
9972fc2f705SBrian Somers       else if (how == CLOSE_STAYDOWN)
9982fc2f705SBrian Somers         datalink_StayDown(dl);
9992fc2f705SBrian Somers       fsm_Close(&dl->physical->link.lcp.fsm);
1000d81ecf9aSBrian Somers       break;
1001e2ebb036SBrian Somers 
1002e2ebb036SBrian Somers     default:
10039c81b87dSBrian Somers       datalink_ComeDown(dl, how);
1004c7cc5030SBrian Somers   }
1005e2ebb036SBrian Somers }
1006c7cc5030SBrian Somers 
1007c7cc5030SBrian Somers void
10089c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how)
1009c7cc5030SBrian Somers {
1010c7cc5030SBrian Somers   /* Carrier is lost */
1011e2ebb036SBrian Somers   switch (dl->state) {
1012e2ebb036SBrian Somers     case DATALINK_OPEN:
1013643f4904SBrian Somers       peerid_Init(&dl->peer);
101409206a6fSBrian Somers       fsm2initial(&dl->physical->link.ccp.fsm);
1015e2ebb036SBrian Somers       /* fall through */
1016e2ebb036SBrian Somers 
101792b09558SBrian Somers     case DATALINK_CBCP:
1018e2ebb036SBrian Somers     case DATALINK_AUTH:
1019e2ebb036SBrian Somers     case DATALINK_LCP:
102009206a6fSBrian Somers       fsm2initial(&dl->physical->link.lcp.fsm);
1021225e259dSBrian Somers       if (dl->state == DATALINK_OPENING)
1022225e259dSBrian Somers         return;			/* we're doing a callback... */
1023e2ebb036SBrian Somers       /* fall through */
1024c7cc5030SBrian Somers 
1025e2ebb036SBrian Somers     default:
10269c81b87dSBrian Somers       datalink_ComeDown(dl, how);
1027c7cc5030SBrian Somers   }
1028e2ebb036SBrian Somers }
1029c7cc5030SBrian Somers 
1030c7cc5030SBrian Somers void
10313006ec67SBrian Somers datalink_StayDown(struct datalink *dl)
10323006ec67SBrian Somers {
10332fc2f705SBrian Somers   dl->dial.tries = -1;
10343006ec67SBrian Somers   dl->reconnect_tries = 0;
10352fc2f705SBrian Somers   dl->stayonline = 0;
10363006ec67SBrian Somers }
1037c7cc5030SBrian Somers 
10389c81b87dSBrian Somers void
10399c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl)
10409c81b87dSBrian Somers {
10412fc2f705SBrian Somers   dl->dial.tries = -1;
10422fc2f705SBrian Somers   dl->reconnect_tries = 0;
10432fc2f705SBrian Somers   dl->stayonline = dl->state >= DATALINK_LCP ? 1 : 0;
10449c81b87dSBrian Somers }
10459c81b87dSBrian Somers 
1046643f4904SBrian Somers int
1047643f4904SBrian Somers datalink_Show(struct cmdargs const *arg)
1048c7cc5030SBrian Somers {
1049643f4904SBrian Somers   prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
1050643f4904SBrian Somers   prompt_Printf(arg->prompt, " State:              %s\n",
1051643f4904SBrian Somers                 datalink_State(arg->cx));
1052643f4904SBrian Somers   prompt_Printf(arg->prompt, " Peer name:          ");
1053643f4904SBrian Somers   if (*arg->cx->peer.authname)
1054643f4904SBrian Somers     prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname);
1055643f4904SBrian Somers   else if (arg->cx->state == DATALINK_OPEN)
1056643f4904SBrian Somers     prompt_Printf(arg->prompt, "None requested\n");
1057565e35e5SBrian Somers   else
1058643f4904SBrian Somers     prompt_Printf(arg->prompt, "N/A\n");
1059643f4904SBrian Somers   prompt_Printf(arg->prompt, " Discriminator:      %s\n",
1060643f4904SBrian Somers                 mp_Enddisc(arg->cx->peer.enddisc.class,
1061643f4904SBrian Somers                            arg->cx->peer.enddisc.address,
1062643f4904SBrian Somers                            arg->cx->peer.enddisc.len));
1063643f4904SBrian Somers 
1064643f4904SBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
1065643f4904SBrian Somers   prompt_Printf(arg->prompt, " Phone List:         %s\n",
1066643f4904SBrian Somers                 arg->cx->cfg.phone.list);
1067643f4904SBrian Somers   if (arg->cx->cfg.dial.max)
1068643f4904SBrian Somers     prompt_Printf(arg->prompt, " Dial tries:         %d, delay ",
1069643f4904SBrian Somers                   arg->cx->cfg.dial.max);
1070565e35e5SBrian Somers   else
1071643f4904SBrian Somers     prompt_Printf(arg->prompt, " Dial tries:         infinite, delay ");
1072b5c347a3SBrian Somers   if (arg->cx->cfg.dial.next_timeout >= 0)
1073643f4904SBrian Somers     prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout);
1074565e35e5SBrian Somers   else
1075643f4904SBrian Somers     prompt_Printf(arg->prompt, "random/");
1076b5c347a3SBrian Somers   if (arg->cx->cfg.dial.timeout >= 0)
1077643f4904SBrian Somers     prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout);
1078565e35e5SBrian Somers   else
1079643f4904SBrian Somers     prompt_Printf(arg->prompt, "random\n");
1080643f4904SBrian Somers   prompt_Printf(arg->prompt, " Reconnect tries:    %d, delay ",
1081643f4904SBrian Somers                 arg->cx->cfg.reconnect.max);
1082643f4904SBrian Somers   if (arg->cx->cfg.reconnect.timeout > 0)
1083643f4904SBrian Somers     prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout);
1084643f4904SBrian Somers   else
1085643f4904SBrian Somers     prompt_Printf(arg->prompt, "random\n");
108692b09558SBrian Somers   prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type ==
108792b09558SBrian Somers                 PHYS_DIRECT ?  "accepted: " : "requested:");
108892b09558SBrian Somers   if (!arg->cx->cfg.callback.opmask)
108992b09558SBrian Somers     prompt_Printf(arg->prompt, "none\n");
109092b09558SBrian Somers   else {
109192b09558SBrian Somers     int comma = 0;
109292b09558SBrian Somers 
109392b09558SBrian Somers     if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
109492b09558SBrian Somers       prompt_Printf(arg->prompt, "none");
109592b09558SBrian Somers       comma = 1;
109692b09558SBrian Somers     }
109792b09558SBrian Somers     if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
109892b09558SBrian Somers       prompt_Printf(arg->prompt, "%sauth", comma ? ", " : "");
109992b09558SBrian Somers       comma = 1;
110092b09558SBrian Somers     }
110192b09558SBrian Somers     if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
110292b09558SBrian Somers       prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : "");
110392b09558SBrian Somers       if (arg->cx->physical->type != PHYS_DIRECT)
110492b09558SBrian Somers         prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg);
110592b09558SBrian Somers       comma = 1;
110692b09558SBrian Somers     }
110792b09558SBrian Somers     if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
110892b09558SBrian Somers       prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : "");
110992b09558SBrian Somers       prompt_Printf(arg->prompt, " CBCP:               delay: %ds\n",
111092b09558SBrian Somers                     arg->cx->cfg.cbcp.delay);
1111cf784a89SBrian Somers       prompt_Printf(arg->prompt, "                     phone: ");
1112cf784a89SBrian Somers       if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) {
1113cf784a89SBrian Somers         if (arg->cx->physical->type & PHYS_DIRECT)
1114cf784a89SBrian Somers           prompt_Printf(arg->prompt, "Caller decides\n");
1115cf784a89SBrian Somers         else
1116cf784a89SBrian Somers           prompt_Printf(arg->prompt, "Dialback server decides\n");
1117cf784a89SBrian Somers       } else
1118cf784a89SBrian Somers         prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone);
111992b09558SBrian Somers       prompt_Printf(arg->prompt, "                     timeout: %lds\n",
112092b09558SBrian Somers                     arg->cx->cfg.cbcp.fsmretry);
112192b09558SBrian Somers     } else
112292b09558SBrian Somers       prompt_Printf(arg->prompt, "\n");
112392b09558SBrian Somers   }
112492b09558SBrian Somers 
1125643f4904SBrian Somers   prompt_Printf(arg->prompt, " Dial Script:        %s\n",
1126643f4904SBrian Somers                 arg->cx->cfg.script.dial);
1127643f4904SBrian Somers   prompt_Printf(arg->prompt, " Login Script:       %s\n",
1128643f4904SBrian Somers                 arg->cx->cfg.script.login);
1129c116e0c0SBrian Somers   prompt_Printf(arg->prompt, " Logout Script:      %s\n",
1130c116e0c0SBrian Somers                 arg->cx->cfg.script.logout);
1131643f4904SBrian Somers   prompt_Printf(arg->prompt, " Hangup Script:      %s\n",
1132643f4904SBrian Somers                 arg->cx->cfg.script.hangup);
1133643f4904SBrian Somers   return 0;
1134565e35e5SBrian Somers }
1135565e35e5SBrian Somers 
1136565e35e5SBrian Somers int
1137565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg)
1138565e35e5SBrian Somers {
113925092092SBrian Somers   if (arg->argc == arg->argn+2) {
114025092092SBrian Somers     arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]);
114125092092SBrian Somers     arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]);
1142565e35e5SBrian Somers     return 0;
1143565e35e5SBrian Somers   }
1144565e35e5SBrian Somers   return -1;
1145565e35e5SBrian Somers }
1146565e35e5SBrian Somers 
1147565e35e5SBrian Somers int
1148565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg)
1149565e35e5SBrian Somers {
1150c11e57a3SBrian Somers   const char *sep, *osep;
1151c11e57a3SBrian Somers   int timeout, inc, maxinc, tries;
1152565e35e5SBrian Somers 
115325092092SBrian Somers   if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) {
115425092092SBrian Somers     if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 &&
115525092092SBrian Somers 	(arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) {
1156565e35e5SBrian Somers       arg->cx->cfg.dial.timeout = -1;
1157565e35e5SBrian Somers       randinit();
1158565e35e5SBrian Somers     } else {
115925092092SBrian Somers       timeout = atoi(arg->argv[arg->argn]);
1160565e35e5SBrian Somers 
1161565e35e5SBrian Somers       if (timeout >= 0)
1162565e35e5SBrian Somers 	arg->cx->cfg.dial.timeout = timeout;
1163565e35e5SBrian Somers       else {
1164dd7e2610SBrian Somers 	log_Printf(LogWARN, "Invalid redial timeout\n");
1165565e35e5SBrian Somers 	return -1;
1166565e35e5SBrian Somers       }
1167565e35e5SBrian Somers     }
1168565e35e5SBrian Somers 
1169c11e57a3SBrian Somers     sep = strchr(arg->argv[arg->argn], '+');
1170c11e57a3SBrian Somers     if (sep) {
1171c11e57a3SBrian Somers       inc = atoi(++sep);
1172c11e57a3SBrian Somers       osep = sep;
1173c11e57a3SBrian Somers       if (inc >= 0)
1174c11e57a3SBrian Somers         arg->cx->cfg.dial.inc = inc;
1175c11e57a3SBrian Somers       else {
1176c11e57a3SBrian Somers         log_Printf(LogWARN, "Invalid timeout increment\n");
1177c11e57a3SBrian Somers         return -1;
1178c11e57a3SBrian Somers       }
1179c11e57a3SBrian Somers       sep = strchr(sep, '-');
1180c11e57a3SBrian Somers       if (sep) {
1181c11e57a3SBrian Somers         maxinc = atoi(++sep);
1182c11e57a3SBrian Somers         if (maxinc >= 0)
1183c11e57a3SBrian Somers           arg->cx->cfg.dial.maxinc = maxinc;
1184c11e57a3SBrian Somers         else {
1185c11e57a3SBrian Somers           log_Printf(LogWARN, "Invalid maximum timeout increments\n");
1186c11e57a3SBrian Somers           return -1;
1187c11e57a3SBrian Somers         }
1188c11e57a3SBrian Somers       } else {
1189c11e57a3SBrian Somers         /* Default timeout increment */
1190c11e57a3SBrian Somers         arg->cx->cfg.dial.maxinc = 10;
1191c11e57a3SBrian Somers         sep = osep;
1192c11e57a3SBrian Somers       }
1193c11e57a3SBrian Somers     } else {
1194c11e57a3SBrian Somers       /* Default timeout increment & max increment */
1195c11e57a3SBrian Somers       arg->cx->cfg.dial.inc = 0;
1196c11e57a3SBrian Somers       arg->cx->cfg.dial.maxinc = 10;
1197c11e57a3SBrian Somers       sep = arg->argv[arg->argn];
1198c11e57a3SBrian Somers     }
1199c11e57a3SBrian Somers 
1200c11e57a3SBrian Somers     sep = strchr(sep, '.');
1201c11e57a3SBrian Somers     if (sep) {
1202c11e57a3SBrian Somers       if (strcasecmp(++sep, "random") == 0) {
1203565e35e5SBrian Somers 	arg->cx->cfg.dial.next_timeout = -1;
1204565e35e5SBrian Somers 	randinit();
1205565e35e5SBrian Somers       } else {
1206c11e57a3SBrian Somers 	timeout = atoi(sep);
1207565e35e5SBrian Somers 	if (timeout >= 0)
1208565e35e5SBrian Somers 	  arg->cx->cfg.dial.next_timeout = timeout;
1209565e35e5SBrian Somers 	else {
1210dd7e2610SBrian Somers 	  log_Printf(LogWARN, "Invalid next redial timeout\n");
1211565e35e5SBrian Somers 	  return -1;
1212565e35e5SBrian Somers 	}
1213565e35e5SBrian Somers       }
1214565e35e5SBrian Somers     } else
1215565e35e5SBrian Somers       /* Default next timeout */
1216565e35e5SBrian Somers       arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
1217565e35e5SBrian Somers 
121825092092SBrian Somers     if (arg->argc == arg->argn+2) {
121925092092SBrian Somers       tries = atoi(arg->argv[arg->argn+1]);
1220565e35e5SBrian Somers 
1221565e35e5SBrian Somers       if (tries >= 0) {
1222565e35e5SBrian Somers 	arg->cx->cfg.dial.max = tries;
1223565e35e5SBrian Somers       } else {
1224dd7e2610SBrian Somers 	log_Printf(LogWARN, "Invalid retry value\n");
1225565e35e5SBrian Somers 	return 1;
1226565e35e5SBrian Somers       }
1227565e35e5SBrian Somers     }
1228565e35e5SBrian Somers     return 0;
1229565e35e5SBrian Somers   }
1230c11e57a3SBrian Somers 
1231565e35e5SBrian Somers   return -1;
1232c7cc5030SBrian Somers }
1233c7cc5030SBrian Somers 
1234182c898aSBrian Somers static const char * const states[] = {
1235565e35e5SBrian Somers   "closed",
1236565e35e5SBrian Somers   "opening",
1237565e35e5SBrian Somers   "hangup",
1238565e35e5SBrian Somers   "dial",
1239eb6e5e05SBrian Somers   "carrier",
1240c116e0c0SBrian Somers   "logout",
1241565e35e5SBrian Somers   "login",
1242565e35e5SBrian Somers   "ready",
1243565e35e5SBrian Somers   "lcp",
1244565e35e5SBrian Somers   "auth",
124592b09558SBrian Somers   "cbcp",
1246565e35e5SBrian Somers   "open"
1247c7cc5030SBrian Somers };
1248c7cc5030SBrian Somers 
1249643f4904SBrian Somers const char *
1250c7cc5030SBrian Somers datalink_State(struct datalink *dl)
1251c7cc5030SBrian Somers {
1252c7cc5030SBrian Somers   if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
1253c7cc5030SBrian Somers     return "unknown";
1254c7cc5030SBrian Somers   return states[dl->state];
1255c7cc5030SBrian Somers }
12566f384573SBrian Somers 
12579ae58882SBrian Somers static void
12589ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state)
12599ae58882SBrian Somers {
12609ae58882SBrian Somers   if (state != dl->state) {
12619ae58882SBrian Somers     if (state >= 0 && state < sizeof states / sizeof states[0]) {
12629ae58882SBrian Somers       log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl),
12639ae58882SBrian Somers                  states[state]);
12649ae58882SBrian Somers       dl->state = state;
12659ae58882SBrian Somers     } else
12669ae58882SBrian Somers       log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state);
12679ae58882SBrian Somers   }
12689ae58882SBrian Somers }
12699ae58882SBrian Somers 
12706f384573SBrian Somers struct datalink *
127196c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov,
127287c3786eSBrian Somers              int fd, int *auxfd, int *nauxfd)
12736f384573SBrian Somers {
1274b7c5748eSBrian Somers   struct datalink *dl, *cdl;
1275479508cfSBrian Somers   struct fsm_retry copy;
1276b7c5748eSBrian Somers   char *oname;
12776f384573SBrian Somers 
127896c9bb21SBrian Somers   dl = (struct datalink *)iov[(*niov)++].iov_base;
127996c9bb21SBrian Somers   dl->name = iov[*niov].iov_base;
12806f384573SBrian Somers 
128196c9bb21SBrian Somers   if (dl->name[DATALINK_MAXNAME-1]) {
128296c9bb21SBrian Somers     dl->name[DATALINK_MAXNAME-1] = '\0';
128396c9bb21SBrian Somers     if (strlen(dl->name) == DATALINK_MAXNAME - 1)
128496c9bb21SBrian Somers       log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name);
12856f384573SBrian Somers   }
1286b7c5748eSBrian Somers 
1287b7c5748eSBrian Somers   /* Make sure the name is unique ! */
1288b7c5748eSBrian Somers   oname = NULL;
1289b7c5748eSBrian Somers   do {
1290b7c5748eSBrian Somers     for (cdl = bundle->links; cdl; cdl = cdl->next)
1291b7c5748eSBrian Somers       if (!strcasecmp(dl->name, cdl->name)) {
1292b7c5748eSBrian Somers         if (oname)
1293b7c5748eSBrian Somers           free(datalink_NextName(dl));
1294b7c5748eSBrian Somers         else
1295b7c5748eSBrian Somers           oname = datalink_NextName(dl);
1296b7c5748eSBrian Somers         break;	/* Keep renaming 'till we have no conflicts */
1297b7c5748eSBrian Somers       }
1298b7c5748eSBrian Somers   } while (cdl);
1299b7c5748eSBrian Somers 
1300b7c5748eSBrian Somers   if (oname) {
1301b7c5748eSBrian Somers     log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name);
1302b7c5748eSBrian Somers     free(oname);
1303b7c5748eSBrian Somers   } else {
130496c9bb21SBrian Somers     dl->name = strdup(dl->name);
1305b7c5748eSBrian Somers     free(iov[*niov].iov_base);
1306b7c5748eSBrian Somers   }
1307b7c5748eSBrian Somers   (*niov)++;
13086f384573SBrian Somers 
13096f384573SBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
13106f384573SBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
13116f384573SBrian Somers   dl->desc.IsSet = datalink_IsSet;
13126f384573SBrian Somers   dl->desc.Read = datalink_Read;
13136f384573SBrian Somers   dl->desc.Write = datalink_Write;
13146f384573SBrian Somers 
13156f384573SBrian Somers   mp_linkInit(&dl->mp);
13166f384573SBrian Somers   *dl->phone.list = '\0';
13176f384573SBrian Somers   dl->phone.next = NULL;
13186f384573SBrian Somers   dl->phone.alt = NULL;
13196f384573SBrian Somers   dl->phone.chosen = "N/A";
13206f384573SBrian Somers 
13216f384573SBrian Somers   dl->bundle = bundle;
13226f384573SBrian Somers   dl->next = NULL;
1323c11e57a3SBrian Somers   memset(&dl->dial.timer, '\0', sizeof dl->dial.timer);
1324c11e57a3SBrian Somers   dl->dial.tries = 0;
13256f384573SBrian Somers   dl->reconnect_tries = 0;
13266f384573SBrian Somers   dl->parent = &bundle->fsm;
13276f384573SBrian Somers   dl->fsmp.LayerStart = datalink_LayerStart;
13286f384573SBrian Somers   dl->fsmp.LayerUp = datalink_LayerUp;
13296f384573SBrian Somers   dl->fsmp.LayerDown = datalink_LayerDown;
13306f384573SBrian Somers   dl->fsmp.LayerFinish = datalink_LayerFinish;
13316f384573SBrian Somers   dl->fsmp.object = dl;
13326f384573SBrian Somers 
133387c3786eSBrian Somers   dl->physical = iov2physical(dl, iov, niov, maxiov, fd, auxfd, nauxfd);
133496c9bb21SBrian Somers 
133596c9bb21SBrian Somers   if (!dl->physical) {
13366f384573SBrian Somers     free(dl->name);
13376f384573SBrian Somers     free(dl);
13386f384573SBrian Somers     dl = NULL;
13399ae58882SBrian Somers   } else {
1340479508cfSBrian Somers     copy = dl->pap.cfg.fsm;
1341f0cdd9c0SBrian Somers     pap_Init(&dl->pap, dl->physical);
1342479508cfSBrian Somers     dl->pap.cfg.fsm = copy;
1343f0cdd9c0SBrian Somers 
1344479508cfSBrian Somers     copy = dl->chap.auth.cfg.fsm;
1345f0cdd9c0SBrian Somers     chap_Init(&dl->chap, dl->physical);
1346479508cfSBrian Somers     dl->chap.auth.cfg.fsm = copy;
1347f0cdd9c0SBrian Somers 
134892b09558SBrian Somers     cbcp_Init(&dl->cbcp, dl->physical);
1349c116e0c0SBrian Somers 
1350c116e0c0SBrian Somers     memset(&dl->chat, '\0', sizeof dl->chat);	/* Force buf{start,end} reset */
1351ffcfaec7SBrian Somers     chat_Init(&dl->chat, dl->physical);
13526f384573SBrian Somers 
13539ae58882SBrian Somers     log_Printf(LogPHASE, "%s: Transferred in %s state\n",
13549ae58882SBrian Somers               dl->name, datalink_State(dl));
13559ae58882SBrian Somers   }
13569ae58882SBrian Somers 
13576f384573SBrian Somers   return dl;
13586f384573SBrian Somers }
13596f384573SBrian Somers 
13606f384573SBrian Somers int
136185fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
13622cb305afSBrian Somers              int *auxfd, int *nauxfd)
13636f384573SBrian Somers {
136496c9bb21SBrian Somers   /* If `dl' is NULL, we're allocating before a Fromiov() */
136596c9bb21SBrian Somers   int link_fd;
13666f384573SBrian Somers 
136796c9bb21SBrian Somers   if (dl) {
1368c11e57a3SBrian Somers     timer_Stop(&dl->dial.timer);
136992b09558SBrian Somers     /* The following is purely for the sake of paranoia */
137092b09558SBrian Somers     cbcp_Down(&dl->cbcp);
1371dd7e2610SBrian Somers     timer_Stop(&dl->pap.authtimer);
1372dd7e2610SBrian Somers     timer_Stop(&dl->chap.auth.authtimer);
13736f384573SBrian Somers   }
13746f384573SBrian Somers 
137596c9bb21SBrian Somers   if (*niov >= maxiov - 1) {
137696c9bb21SBrian Somers     log_Printf(LogERROR, "Toiov: No room for datalink !\n");
137796c9bb21SBrian Somers     if (dl) {
13786f384573SBrian Somers       free(dl->name);
13796f384573SBrian Somers       free(dl);
138096c9bb21SBrian Somers     }
138196c9bb21SBrian Somers     return -1;
138296c9bb21SBrian Somers   }
138396c9bb21SBrian Somers 
13842cb305afSBrian Somers   iov[*niov].iov_base = (void *)dl;
138596c9bb21SBrian Somers   iov[(*niov)++].iov_len = sizeof *dl;
13862cb305afSBrian Somers   iov[*niov].iov_base = dl ? realloc(dl->name, DATALINK_MAXNAME) : NULL;
138796c9bb21SBrian Somers   iov[(*niov)++].iov_len = DATALINK_MAXNAME;
138896c9bb21SBrian Somers 
138987c3786eSBrian Somers   link_fd = physical2iov(dl ? dl->physical : NULL, iov, niov, maxiov, auxfd,
13902cb305afSBrian Somers                          nauxfd);
139196c9bb21SBrian Somers 
139296c9bb21SBrian Somers   if (link_fd == -1 && dl) {
139396c9bb21SBrian Somers     free(dl->name);
139496c9bb21SBrian Somers     free(dl);
139596c9bb21SBrian Somers   }
13966f384573SBrian Somers 
13976f384573SBrian Somers   return link_fd;
13986f384573SBrian Somers }
13996f384573SBrian Somers 
140058d55334SBrian Somers void
140158d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name)
140258d55334SBrian Somers {
140358d55334SBrian Somers   free(dl->name);
140458d55334SBrian Somers   dl->physical->link.name = dl->name = strdup(name);
140558d55334SBrian Somers }
140658d55334SBrian Somers 
140784917b87SBrian Somers char *
140884917b87SBrian Somers datalink_NextName(struct datalink *dl)
14096f384573SBrian Somers {
14106f384573SBrian Somers   int f, n;
141184917b87SBrian Somers   char *name, *oname;
14126f384573SBrian Somers 
14136f384573SBrian Somers   n = strlen(dl->name);
14146f384573SBrian Somers   name = (char *)malloc(n+3);
14156f384573SBrian Somers   for (f = n - 1; f >= 0; f--)
14166f384573SBrian Somers     if (!isdigit(dl->name[f]))
14176f384573SBrian Somers       break;
14186f384573SBrian Somers   n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name);
14196f384573SBrian Somers   sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1);
142084917b87SBrian Somers   oname = dl->name;
142154cd8e13SBrian Somers   dl->name = name;
142254cd8e13SBrian Somers   /* our physical link name isn't updated (it probably isn't created yet) */
142384917b87SBrian Somers   return oname;
14246f384573SBrian Somers }
1425dd0645c5SBrian Somers 
1426dd0645c5SBrian Somers int
1427dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode)
1428dd0645c5SBrian Somers {
1429dd0645c5SBrian Somers   if (!physical_SetMode(dl->physical, mode))
1430dd0645c5SBrian Somers     return 0;
1431dd0645c5SBrian Somers   if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
1432dd0645c5SBrian Somers     dl->script.run = 0;
1433dd0645c5SBrian Somers   if (dl->physical->type == PHYS_DIRECT)
1434dd0645c5SBrian Somers     dl->reconnect_tries = 0;
1435f6a4e748SBrian Somers   if (mode & (PHYS_DDIAL|PHYS_BACKGROUND|PHYS_FOREGROUND) &&
1436f6a4e748SBrian Somers       dl->state <= DATALINK_READY)
1437dd0645c5SBrian Somers     datalink_Up(dl, 1, 1);
1438dd0645c5SBrian Somers   return 1;
1439dd0645c5SBrian Somers }
1440c11e57a3SBrian Somers 
1441c11e57a3SBrian Somers int
1442c11e57a3SBrian Somers datalink_GetDialTimeout(struct datalink *dl)
1443c11e57a3SBrian Somers {
1444c11e57a3SBrian Somers   int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc;
1445c11e57a3SBrian Somers 
1446c11e57a3SBrian Somers   if (dl->dial.incs < dl->cfg.dial.maxinc)
1447c11e57a3SBrian Somers     dl->dial.incs++;
1448c11e57a3SBrian Somers 
1449c11e57a3SBrian Somers   return result;
1450c11e57a3SBrian Somers }
1451