xref: /freebsd/usr.sbin/ppp/datalink.c (revision d345321b)
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  *
26d345321bSBrian Somers  *	$Id: datalink.c,v 1.1.2.10 1998/02/17 19:29:09 brian Exp $
273006ec67SBrian Somers  */
283006ec67SBrian Somers 
293006ec67SBrian Somers #include <sys/param.h>
303006ec67SBrian Somers #include <netinet/in.h>
313006ec67SBrian Somers 
323006ec67SBrian Somers #include <alias.h>
33c7cc5030SBrian Somers #include <stdio.h>
343006ec67SBrian Somers #include <stdlib.h>
353006ec67SBrian Somers #include <string.h>
363006ec67SBrian Somers #include <termios.h>
373006ec67SBrian Somers 
383006ec67SBrian Somers #include "command.h"
393006ec67SBrian Somers #include "mbuf.h"
403006ec67SBrian Somers #include "log.h"
413006ec67SBrian Somers #include "defs.h"
423006ec67SBrian Somers #include "loadalias.h"
433006ec67SBrian Somers #include "vars.h"
443006ec67SBrian Somers #include "timer.h"
453006ec67SBrian Somers #include "fsm.h"
463006ec67SBrian Somers #include "lcp.h"
473006ec67SBrian Somers #include "descriptor.h"
483006ec67SBrian Somers #include "hdlc.h"
493006ec67SBrian Somers #include "async.h"
503006ec67SBrian Somers #include "throughput.h"
513006ec67SBrian Somers #include "link.h"
523006ec67SBrian Somers #include "physical.h"
533006ec67SBrian Somers #include "bundle.h"
543006ec67SBrian Somers #include "chat.h"
553006ec67SBrian Somers #include "datalink.h"
563006ec67SBrian Somers #include "ccp.h"
573006ec67SBrian Somers #include "main.h"
583006ec67SBrian Somers #include "modem.h"
593006ec67SBrian Somers #include "iplist.h"
603006ec67SBrian Somers #include "ipcp.h"
61c7cc5030SBrian Somers #include "prompt.h"
62c7cc5030SBrian Somers 
63c7cc5030SBrian Somers static const char *datalink_State(struct datalink *);
643006ec67SBrian Somers 
653006ec67SBrian Somers static void
663006ec67SBrian Somers datalink_OpenTimeout(void *v)
673006ec67SBrian Somers {
683006ec67SBrian Somers   struct datalink *dl = (struct datalink *)v;
693006ec67SBrian Somers 
703006ec67SBrian Somers   StopTimer(&dl->dial_timer);
713006ec67SBrian Somers   if (dl->state == DATALINK_OPENING)
723006ec67SBrian Somers     LogPrintf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
733006ec67SBrian Somers }
743006ec67SBrian Somers 
753006ec67SBrian Somers static void
763006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout)
773006ec67SBrian Somers {
783006ec67SBrian Somers   StopTimer(&dl->dial_timer);
793006ec67SBrian Somers 
803006ec67SBrian Somers   if (Timeout) {
813006ec67SBrian Somers     dl->dial_timer.state = TIMER_STOPPED;
823006ec67SBrian Somers     if (Timeout > 0)
833006ec67SBrian Somers       dl->dial_timer.load = Timeout * SECTICKS;
843006ec67SBrian Somers     else
85e718d1d7SBrian Somers       dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
863006ec67SBrian Somers     dl->dial_timer.func = datalink_OpenTimeout;
873006ec67SBrian Somers     dl->dial_timer.arg = dl;
883006ec67SBrian Somers     StartTimer(&dl->dial_timer);
893006ec67SBrian Somers     if (dl->state == DATALINK_OPENING)
903006ec67SBrian Somers       LogPrintf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
913006ec67SBrian Somers                 dl->name, Timeout);
923006ec67SBrian Somers   }
933006ec67SBrian Somers }
943006ec67SBrian Somers 
953006ec67SBrian Somers static void
963006ec67SBrian Somers datalink_HangupDone(struct datalink *dl)
973006ec67SBrian Somers {
983006ec67SBrian Somers   modem_Close(dl->physical);
993006ec67SBrian Somers 
1003006ec67SBrian Somers   if (!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) {
1013006ec67SBrian Somers     LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
1023006ec67SBrian Somers     dl->state = DATALINK_CLOSED;
1033006ec67SBrian Somers     dl->dial_tries = -1;
1043006ec67SBrian Somers     dl->reconnect_tries = 0;
1053006ec67SBrian Somers     bundle_LinkClosed(dl->bundle, dl);
10673a13b5cSBrian Somers     datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
1073006ec67SBrian Somers   } else {
108aef795ccSBrian Somers     LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name);
1093006ec67SBrian Somers     dl->state = DATALINK_OPENING;
110abff9baeSBrian Somers     if (dl->dial_tries < 0) {
11173a13b5cSBrian Somers       datalink_StartDialTimer(dl, dl->cfg.reconnect_timeout);
11273a13b5cSBrian Somers       dl->dial_tries = dl->cfg.max_dial;
113abff9baeSBrian Somers       dl->reconnect_tries--;
114abff9baeSBrian Somers     } else {
115abff9baeSBrian Somers       dl->dial_tries--;
1163006ec67SBrian Somers       if (VarNextPhone == NULL)
11773a13b5cSBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
1183006ec67SBrian Somers       else
11973a13b5cSBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial_next_timeout);
1203006ec67SBrian Somers     }
121abff9baeSBrian Somers   }
122abff9baeSBrian Somers }
1233006ec67SBrian Somers 
124c5a5a6caSBrian Somers static void
125c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl)
126c5a5a6caSBrian Somers {
127d345321bSBrian Somers   if (!dl->script.packetmode) {
128d345321bSBrian Somers     dl->dial_tries = -1;
129d345321bSBrian Somers     LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name);
130d345321bSBrian Somers     dl->state = DATALINK_READY;
131d345321bSBrian Somers   } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
132c5a5a6caSBrian Somers     dl->dial_tries = 0;
133c5a5a6caSBrian Somers     LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n");
134c5a5a6caSBrian Somers     if (dl->script.run) {
135c5a5a6caSBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
136c5a5a6caSBrian Somers       dl->state = DATALINK_HANGUP;
137c5a5a6caSBrian Somers       modem_Offline(dl->physical);
13873a13b5cSBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1);
139c5a5a6caSBrian Somers     } else
140c5a5a6caSBrian Somers       datalink_HangupDone(dl);
141c5a5a6caSBrian Somers   } else {
142c7cc5030SBrian Somers     dl->dial_tries = -1;
143c5a5a6caSBrian Somers     LogPrintf(LogPHASE, "%s: Entering OPEN state\n", dl->name);
144c5a5a6caSBrian Somers     dl->state = DATALINK_OPEN;
145c7cc5030SBrian Somers 
146c7cc5030SBrian Somers     LcpInit(dl->bundle, dl->physical);
147c7cc5030SBrian Somers     CcpInit(dl->bundle, &dl->physical->link);
148c7cc5030SBrian Somers     FsmUp(&LcpInfo.fsm);
14981b6b898SBrian Somers     LcpInfo.fsm.open_mode = dl->state == DATALINK_READY ? 0 : VarOpenMode;
15081b6b898SBrian Somers     FsmOpen(&LcpInfo.fsm);
151c5a5a6caSBrian Somers   }
152c5a5a6caSBrian Somers }
153c5a5a6caSBrian Somers 
1543006ec67SBrian Somers static int
1553006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
1563006ec67SBrian Somers                    int *n)
1573006ec67SBrian Somers {
1583006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
1593006ec67SBrian Somers   int result;
1603006ec67SBrian Somers 
161310c3babSBrian Somers   result = 0;
1623006ec67SBrian Somers   switch (dl->state) {
1633006ec67SBrian Somers     case DATALINK_CLOSED:
164310c3babSBrian Somers       break;
1653006ec67SBrian Somers 
1663006ec67SBrian Somers     case DATALINK_OPENING:
1673006ec67SBrian Somers       if (dl->dial_timer.state != TIMER_RUNNING) {
1683006ec67SBrian Somers         if (--dl->dial_tries < 0)
1693006ec67SBrian Somers           dl->dial_tries = 0;
1703006ec67SBrian Somers         if (modem_Open(dl->physical, dl->bundle) >= 0) {
171c5a5a6caSBrian Somers           if (dl->script.run) {
1723006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name);
1733006ec67SBrian Somers             dl->state = DATALINK_DIAL;
17473a13b5cSBrian Somers             chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1);
17573a13b5cSBrian Somers             if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
1763006ec67SBrian Somers               LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n",
17773a13b5cSBrian Somers                         dl->name, dl->cfg.max_dial - dl->dial_tries,
17873a13b5cSBrian Somers                         dl->cfg.max_dial);
179c5a5a6caSBrian Somers           } else
180c5a5a6caSBrian Somers             datalink_LoginDone(dl);
1813006ec67SBrian Somers         } else {
18273a13b5cSBrian Somers           if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
1833006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
18473a13b5cSBrian Somers                       dl->cfg.max_dial - dl->dial_tries, dl->cfg.max_dial);
1853006ec67SBrian Somers           else
1863006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem\n");
1873006ec67SBrian Somers 
18873a13b5cSBrian Somers           if (!(mode & MODE_DDIAL) && dl->cfg.max_dial && dl->dial_tries == 0) {
1893006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
1903006ec67SBrian Somers             dl->state = DATALINK_CLOSED;
1913006ec67SBrian Somers             dl->reconnect_tries = 0;
1923006ec67SBrian Somers             dl->dial_tries = -1;
1935b8b8060SBrian Somers             bundle_LinkClosed(dl->bundle, dl);
194c5a5a6caSBrian Somers           }
19573a13b5cSBrian Somers           datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
1963006ec67SBrian Somers         }
1973006ec67SBrian Somers       }
198310c3babSBrian Somers       break;
1993006ec67SBrian Somers 
2003006ec67SBrian Somers     case DATALINK_HANGUP:
2013006ec67SBrian Somers     case DATALINK_DIAL:
2023006ec67SBrian Somers     case DATALINK_LOGIN:
2033006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
2043006ec67SBrian Somers       switch (dl->chat.state) {
2053006ec67SBrian Somers         case CHAT_DONE:
2063006ec67SBrian Somers           /* script succeeded */
2073006ec67SBrian Somers           switch(dl->state) {
2083006ec67SBrian Somers             case DATALINK_HANGUP:
2093006ec67SBrian Somers               datalink_HangupDone(dl);
2103006ec67SBrian Somers               break;
2113006ec67SBrian Somers             case DATALINK_DIAL:
2123006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name);
2133006ec67SBrian Somers               dl->state = DATALINK_LOGIN;
21473a13b5cSBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0);
2153006ec67SBrian Somers               break;
2163006ec67SBrian Somers             case DATALINK_LOGIN:
217c5a5a6caSBrian Somers               datalink_LoginDone(dl);
2183006ec67SBrian Somers               break;
2193006ec67SBrian Somers           }
2203006ec67SBrian Somers           break;
2213006ec67SBrian Somers         case CHAT_FAILED:
2223006ec67SBrian Somers           /* Going down - script failed */
2233006ec67SBrian Somers           LogPrintf(LogWARN, "Chat script failed\n");
2243006ec67SBrian Somers           switch(dl->state) {
2253006ec67SBrian Somers             case DATALINK_HANGUP:
2263006ec67SBrian Somers               datalink_HangupDone(dl);
2273006ec67SBrian Somers               break;
2283006ec67SBrian Somers             case DATALINK_DIAL:
2293006ec67SBrian Somers             case DATALINK_LOGIN:
2303006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
2313006ec67SBrian Somers               dl->state = DATALINK_HANGUP;
2323006ec67SBrian Somers               modem_Offline(dl->physical);
23373a13b5cSBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1);
2343006ec67SBrian Somers               break;
2353006ec67SBrian Somers           }
2363006ec67SBrian Somers           break;
2373006ec67SBrian Somers       }
2383006ec67SBrian Somers       break;
239c7cc5030SBrian Somers 
240c7cc5030SBrian Somers     case DATALINK_READY:
2413006ec67SBrian Somers     case DATALINK_OPEN:
2423006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
2433006ec67SBrian Somers       break;
2443006ec67SBrian Somers   }
2453006ec67SBrian Somers   return result;
2463006ec67SBrian Somers }
2473006ec67SBrian Somers 
2483006ec67SBrian Somers static int
2493006ec67SBrian Somers datalink_IsSet(struct descriptor *d, fd_set *fdset)
2503006ec67SBrian Somers {
2513006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
2523006ec67SBrian Somers 
2533006ec67SBrian Somers   switch (dl->state) {
2543006ec67SBrian Somers     case DATALINK_CLOSED:
255c7cc5030SBrian Somers     case DATALINK_OPENING:
2563006ec67SBrian Somers       break;
257c7cc5030SBrian Somers 
2583006ec67SBrian Somers     case DATALINK_HANGUP:
2593006ec67SBrian Somers     case DATALINK_DIAL:
2603006ec67SBrian Somers     case DATALINK_LOGIN:
2613006ec67SBrian Somers       return descriptor_IsSet(&dl->chat.desc, fdset);
262c7cc5030SBrian Somers 
263c7cc5030SBrian Somers     case DATALINK_READY:
2643006ec67SBrian Somers     case DATALINK_OPEN:
2653006ec67SBrian Somers       return descriptor_IsSet(&dl->physical->desc, fdset);
2663006ec67SBrian Somers   }
2673006ec67SBrian Somers   return 0;
2683006ec67SBrian Somers }
2693006ec67SBrian Somers 
2703006ec67SBrian Somers static void
2713006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
2723006ec67SBrian Somers {
2733006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
2743006ec67SBrian Somers 
2753006ec67SBrian Somers   switch (dl->state) {
2763006ec67SBrian Somers     case DATALINK_CLOSED:
277c7cc5030SBrian Somers     case DATALINK_OPENING:
2783006ec67SBrian Somers       break;
279c7cc5030SBrian Somers 
2803006ec67SBrian Somers     case DATALINK_HANGUP:
2813006ec67SBrian Somers     case DATALINK_DIAL:
2823006ec67SBrian Somers     case DATALINK_LOGIN:
2833006ec67SBrian Somers       descriptor_Read(&dl->chat.desc, bundle, fdset);
2843006ec67SBrian Somers       break;
285c7cc5030SBrian Somers 
286c7cc5030SBrian Somers     case DATALINK_READY:
2873006ec67SBrian Somers     case DATALINK_OPEN:
2883006ec67SBrian Somers       descriptor_Read(&dl->physical->desc, bundle, fdset);
2893006ec67SBrian Somers       break;
2903006ec67SBrian Somers   }
2913006ec67SBrian Somers }
2923006ec67SBrian Somers 
2933006ec67SBrian Somers static void
2943006ec67SBrian Somers datalink_Write(struct descriptor *d, const fd_set *fdset)
2953006ec67SBrian Somers {
2963006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
2973006ec67SBrian Somers 
2983006ec67SBrian Somers   switch (dl->state) {
2993006ec67SBrian Somers     case DATALINK_CLOSED:
300c7cc5030SBrian Somers     case DATALINK_OPENING:
3013006ec67SBrian Somers       break;
302c7cc5030SBrian Somers 
3033006ec67SBrian Somers     case DATALINK_HANGUP:
3043006ec67SBrian Somers     case DATALINK_DIAL:
3053006ec67SBrian Somers     case DATALINK_LOGIN:
3063006ec67SBrian Somers       descriptor_Write(&dl->chat.desc, fdset);
3073006ec67SBrian Somers       break;
308c7cc5030SBrian Somers 
309c7cc5030SBrian Somers     case DATALINK_READY:
3103006ec67SBrian Somers     case DATALINK_OPEN:
3113006ec67SBrian Somers       descriptor_Write(&dl->physical->desc, fdset);
3123006ec67SBrian Somers       break;
3133006ec67SBrian Somers   }
3143006ec67SBrian Somers }
3153006ec67SBrian Somers 
3163006ec67SBrian Somers struct datalink *
3173006ec67SBrian Somers datalink_Create(const char *name, struct bundle *bundle)
3183006ec67SBrian Somers {
3193006ec67SBrian Somers   struct datalink *dl;
3203006ec67SBrian Somers 
3213006ec67SBrian Somers   dl = (struct datalink *)malloc(sizeof(struct datalink));
3223006ec67SBrian Somers   if (dl == NULL)
3233006ec67SBrian Somers     return dl;
3243006ec67SBrian Somers 
3253006ec67SBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
3263006ec67SBrian Somers   dl->desc.next = NULL;
3273006ec67SBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
3283006ec67SBrian Somers   dl->desc.IsSet = datalink_IsSet;
3293006ec67SBrian Somers   dl->desc.Read = datalink_Read;
3303006ec67SBrian Somers   dl->desc.Write = datalink_Write;
3315b8b8060SBrian Somers 
332e718d1d7SBrian Somers   dl->state = DATALINK_CLOSED;
333e718d1d7SBrian Somers 
33473a13b5cSBrian Somers   *dl->cfg.script.dial = '\0';
33573a13b5cSBrian Somers   *dl->cfg.script.login = '\0';
33673a13b5cSBrian Somers   *dl->cfg.script.hangup = '\0';
337c7cc5030SBrian Somers   dl->script.run = 1;
338c7cc5030SBrian Somers   dl->script.packetmode = 1;
3395b8b8060SBrian Somers 
3403006ec67SBrian Somers   dl->bundle = bundle;
3413006ec67SBrian Somers   dl->next = NULL;
342e718d1d7SBrian Somers 
3433006ec67SBrian Somers   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
344e718d1d7SBrian Somers 
3453006ec67SBrian Somers   dl->dial_tries = 0;
34673a13b5cSBrian Somers   dl->cfg.max_dial = 1;
34773a13b5cSBrian Somers   dl->cfg.dial_timeout = DIAL_TIMEOUT;
34873a13b5cSBrian Somers   dl->cfg.dial_next_timeout = DIAL_NEXT_TIMEOUT;
349e718d1d7SBrian Somers 
350abff9baeSBrian Somers   dl->reconnect_tries = 0;
35173a13b5cSBrian Somers   dl->cfg.max_reconnect = 0;
35273a13b5cSBrian Somers   dl->cfg.reconnect_timeout = RECONNECT_TIMEOUT;
353abff9baeSBrian Somers 
3543006ec67SBrian Somers   dl->name = strdup(name);
3553006ec67SBrian Somers   if ((dl->physical = modem_Create(dl->name)) == NULL) {
3563006ec67SBrian Somers     free(dl->name);
3573006ec67SBrian Somers     free(dl);
3583006ec67SBrian Somers     return NULL;
3593006ec67SBrian Somers   }
360c5a5a6caSBrian Somers   chat_Init(&dl->chat, dl->physical, NULL, 1);
3613006ec67SBrian Somers 
3623006ec67SBrian Somers   IpcpDefAddress();
3633006ec67SBrian Somers   LcpInit(dl->bundle, dl->physical);
3643006ec67SBrian Somers   CcpInit(dl->bundle, &dl->physical->link);
3653006ec67SBrian Somers 
366c7cc5030SBrian Somers   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
3673006ec67SBrian Somers 
3683006ec67SBrian Somers   return dl;
3693006ec67SBrian Somers }
3703006ec67SBrian Somers 
3713006ec67SBrian Somers struct datalink *
3723006ec67SBrian Somers datalink_Destroy(struct datalink *dl)
3733006ec67SBrian Somers {
3743006ec67SBrian Somers   struct datalink *result;
3753006ec67SBrian Somers 
3763006ec67SBrian Somers   if (dl->state != DATALINK_CLOSED)
377c7cc5030SBrian Somers     LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n",
378c7cc5030SBrian Somers               datalink_State(dl));
3793006ec67SBrian Somers 
3803006ec67SBrian Somers   result = dl->next;
3813006ec67SBrian Somers   chat_Destroy(&dl->chat);
3823006ec67SBrian Somers   link_Destroy(&dl->physical->link);
3833006ec67SBrian Somers   free(dl->name);
3843006ec67SBrian Somers   free(dl);
3853006ec67SBrian Somers 
3863006ec67SBrian Somers   return result;
3873006ec67SBrian Somers }
3883006ec67SBrian Somers 
3893006ec67SBrian Somers void
390c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode)
3913006ec67SBrian Somers {
392c7cc5030SBrian Somers   switch (dl->state) {
393c7cc5030SBrian Somers     case DATALINK_CLOSED:
3943006ec67SBrian Somers       LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name);
3953006ec67SBrian Somers       dl->state = DATALINK_OPENING;
39673a13b5cSBrian Somers       dl->reconnect_tries = dl->cfg.max_reconnect;
39773a13b5cSBrian Somers       dl->dial_tries = dl->cfg.max_dial;
398c5a5a6caSBrian Somers       dl->script.run = runscripts;
399c5a5a6caSBrian Somers       dl->script.packetmode = packetmode;
400c7cc5030SBrian Somers       break;
401c7cc5030SBrian Somers 
402c7cc5030SBrian Somers     case DATALINK_OPENING:
403c7cc5030SBrian Somers       if (!dl->script.run && runscripts)
404c7cc5030SBrian Somers         dl->script.run = 1;
405c7cc5030SBrian Somers       /* fall through */
406c7cc5030SBrian Somers 
407c7cc5030SBrian Somers     case DATALINK_DIAL:
408c7cc5030SBrian Somers     case DATALINK_LOGIN:
409c7cc5030SBrian Somers     case DATALINK_READY:
410c7cc5030SBrian Somers       if (!dl->script.packetmode && packetmode) {
411c7cc5030SBrian Somers         dl->script.packetmode = 1;
412c7cc5030SBrian Somers         if (dl->state == DATALINK_READY)
413c7cc5030SBrian Somers           datalink_LoginDone(dl);
414c7cc5030SBrian Somers       }
415c7cc5030SBrian Somers       break;
4163006ec67SBrian Somers   }
4173006ec67SBrian Somers }
4183006ec67SBrian Somers 
419c7cc5030SBrian Somers static void
420c7cc5030SBrian Somers datalink_ComeDown(struct datalink *dl, int stay)
4213006ec67SBrian Somers {
4223006ec67SBrian Somers   if (stay) {
4233006ec67SBrian Somers     dl->dial_tries = -1;
4243006ec67SBrian Somers     dl->reconnect_tries = 0;
4253006ec67SBrian Somers   }
426c5a5a6caSBrian Somers 
427c5a5a6caSBrian Somers   if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
428c5a5a6caSBrian Somers     modem_Offline(dl->physical);
429c5a5a6caSBrian Somers     if (dl->script.run) {
430c5a5a6caSBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
431c5a5a6caSBrian Somers       dl->state = DATALINK_HANGUP;
43273a13b5cSBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1);
433c5a5a6caSBrian Somers     } else
434c5a5a6caSBrian Somers       datalink_HangupDone(dl);
435c5a5a6caSBrian Somers   }
4363006ec67SBrian Somers }
4373006ec67SBrian Somers 
4383006ec67SBrian Somers void
439c7cc5030SBrian Somers datalink_Close(struct datalink *dl, int stay)
440c7cc5030SBrian Somers {
441c7cc5030SBrian Somers   /* Please close */
442c7cc5030SBrian Somers   if (dl->state == DATALINK_OPEN) {
443c7cc5030SBrian Somers     FsmClose(&CcpInfo.fsm);
444c7cc5030SBrian Somers     FsmClose(&LcpInfo.fsm);
445c7cc5030SBrian Somers     if (stay) {
446c7cc5030SBrian Somers       dl->dial_tries = -1;
447c7cc5030SBrian Somers       dl->reconnect_tries = 0;
448c7cc5030SBrian Somers     }
449c7cc5030SBrian Somers   } else
450c7cc5030SBrian Somers     datalink_ComeDown(dl, stay);
451c7cc5030SBrian Somers }
452c7cc5030SBrian Somers 
453c7cc5030SBrian Somers void
454c7cc5030SBrian Somers datalink_Down(struct datalink *dl, int stay)
455c7cc5030SBrian Somers {
456c7cc5030SBrian Somers   /* Carrier is lost */
457c7cc5030SBrian Somers   if (dl->state == DATALINK_OPEN) {
458c7cc5030SBrian Somers     FsmDown(&CcpInfo.fsm);
459c7cc5030SBrian Somers     FsmClose(&CcpInfo.fsm);
460c7cc5030SBrian Somers     FsmDown(&LcpInfo.fsm);
461c7cc5030SBrian Somers     if (stay)
462c7cc5030SBrian Somers       FsmClose(&LcpInfo.fsm);
463c7cc5030SBrian Somers     else
464c7cc5030SBrian Somers       FsmOpen(&CcpInfo.fsm);
465c7cc5030SBrian Somers   }
466c7cc5030SBrian Somers 
467c7cc5030SBrian Somers   datalink_ComeDown(dl, stay);
468c7cc5030SBrian Somers }
469c7cc5030SBrian Somers 
470c7cc5030SBrian Somers void
4713006ec67SBrian Somers datalink_StayDown(struct datalink *dl)
4723006ec67SBrian Somers {
4733006ec67SBrian Somers   dl->reconnect_tries = 0;
4743006ec67SBrian Somers }
475c7cc5030SBrian Somers 
476c7cc5030SBrian Somers void
477c7cc5030SBrian Somers datalink_Show(struct datalink *dl)
478c7cc5030SBrian Somers {
479c7cc5030SBrian Somers   prompt_Printf(&prompt, "Link %s: State %s\n", dl->name, datalink_State(dl));
480c7cc5030SBrian Somers }
481c7cc5030SBrian Somers 
482c7cc5030SBrian Somers static char *states[] = {
483c7cc5030SBrian Somers   "CLOSED",
484c7cc5030SBrian Somers   "OPENING",
485c7cc5030SBrian Somers   "HANGUP",
486c7cc5030SBrian Somers   "DIAL",
487c7cc5030SBrian Somers   "LOGIN",
488c7cc5030SBrian Somers   "READY",
489c7cc5030SBrian Somers   "OPEN"
490c7cc5030SBrian Somers };
491c7cc5030SBrian Somers 
492c7cc5030SBrian Somers static const char *
493c7cc5030SBrian Somers datalink_State(struct datalink *dl)
494c7cc5030SBrian Somers {
495c7cc5030SBrian Somers   if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
496c7cc5030SBrian Somers     return "unknown";
497c7cc5030SBrian Somers   return states[dl->state];
498c7cc5030SBrian Somers }
499