xref: /freebsd/usr.sbin/ppp/datalink.c (revision 643f4904)
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  *
26643f4904SBrian Somers  *	$Id: datalink.c,v 1.1.2.45 1998/04/23 18:56:09 brian Exp $
273006ec67SBrian Somers  */
283006ec67SBrian Somers 
292764b86aSBrian Somers #include <sys/types.h>
303006ec67SBrian Somers #include <netinet/in.h>
31eaa4df37SBrian Somers #include <netinet/in_systm.h>
32eaa4df37SBrian Somers #include <netinet/ip.h>
333006ec67SBrian Somers 
34c7cc5030SBrian Somers #include <stdio.h>
353006ec67SBrian Somers #include <stdlib.h>
363006ec67SBrian Somers #include <string.h>
373006ec67SBrian Somers #include <termios.h>
383006ec67SBrian Somers 
393006ec67SBrian Somers #include "mbuf.h"
403006ec67SBrian Somers #include "log.h"
413006ec67SBrian Somers #include "defs.h"
423006ec67SBrian Somers #include "timer.h"
433006ec67SBrian Somers #include "fsm.h"
443006ec67SBrian Somers #include "lcp.h"
453006ec67SBrian Somers #include "descriptor.h"
46879ed6faSBrian Somers #include "lqr.h"
473006ec67SBrian Somers #include "hdlc.h"
483006ec67SBrian Somers #include "async.h"
493006ec67SBrian Somers #include "throughput.h"
503b0f8d2eSBrian Somers #include "ccp.h"
513006ec67SBrian Somers #include "link.h"
523006ec67SBrian Somers #include "physical.h"
535828db6dSBrian Somers #include "iplist.h"
54eaa4df37SBrian Somers #include "slcompress.h"
555828db6dSBrian Somers #include "ipcp.h"
565ca5389aSBrian Somers #include "filter.h"
573b0f8d2eSBrian Somers #include "mp.h"
583006ec67SBrian Somers #include "bundle.h"
593006ec67SBrian Somers #include "chat.h"
60e2ebb036SBrian Somers #include "auth.h"
613006ec67SBrian Somers #include "modem.h"
62c7cc5030SBrian Somers #include "prompt.h"
63e2ebb036SBrian Somers #include "lcpproto.h"
64e2ebb036SBrian Somers #include "pap.h"
65e2ebb036SBrian Somers #include "chap.h"
66565e35e5SBrian Somers #include "command.h"
67e2ebb036SBrian Somers #include "datalink.h"
68c7cc5030SBrian Somers 
69030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *);
703006ec67SBrian Somers 
713006ec67SBrian Somers static void
723006ec67SBrian Somers datalink_OpenTimeout(void *v)
733006ec67SBrian Somers {
743006ec67SBrian Somers   struct datalink *dl = (struct datalink *)v;
753006ec67SBrian Somers 
763006ec67SBrian Somers   StopTimer(&dl->dial_timer);
773006ec67SBrian Somers   if (dl->state == DATALINK_OPENING)
783006ec67SBrian Somers     LogPrintf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
793006ec67SBrian Somers }
803006ec67SBrian Somers 
813006ec67SBrian Somers static void
823006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout)
833006ec67SBrian Somers {
843006ec67SBrian Somers   StopTimer(&dl->dial_timer);
853006ec67SBrian Somers 
863006ec67SBrian Somers   if (Timeout) {
873006ec67SBrian Somers     if (Timeout > 0)
883006ec67SBrian Somers       dl->dial_timer.load = Timeout * SECTICKS;
893006ec67SBrian Somers     else
90e718d1d7SBrian Somers       dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
913006ec67SBrian Somers     dl->dial_timer.func = datalink_OpenTimeout;
923b0f8d2eSBrian Somers     dl->dial_timer.name = "dial";
933006ec67SBrian Somers     dl->dial_timer.arg = dl;
943006ec67SBrian Somers     StartTimer(&dl->dial_timer);
953006ec67SBrian Somers     if (dl->state == DATALINK_OPENING)
963006ec67SBrian Somers       LogPrintf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
973006ec67SBrian Somers                 dl->name, Timeout);
983006ec67SBrian Somers   }
993006ec67SBrian Somers }
1003006ec67SBrian Somers 
1013006ec67SBrian Somers static void
1023006ec67SBrian Somers datalink_HangupDone(struct datalink *dl)
1033006ec67SBrian Somers {
104030e4ebbSBrian Somers   if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp &&
105030e4ebbSBrian Somers       Physical_GetFD(dl->physical) != -1) {
106030e4ebbSBrian Somers     /* Don't close our modem if the link is dedicated */
107030e4ebbSBrian Somers     datalink_LoginDone(dl);
108030e4ebbSBrian Somers     return;
109030e4ebbSBrian Somers   }
110030e4ebbSBrian Somers 
1113006ec67SBrian Somers   modem_Close(dl->physical);
112565e35e5SBrian Somers   dl->phone.chosen = "N/A";
1133006ec67SBrian Somers 
1143b0f8d2eSBrian Somers   if (dl->bundle->CleaningUp ||
115565e35e5SBrian Somers       (dl->physical->type == PHYS_STDIN) ||
1163b0f8d2eSBrian Somers       ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) &&
117565e35e5SBrian Somers        !(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)))) {
1183006ec67SBrian Somers     LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
1193006ec67SBrian Somers     dl->state = DATALINK_CLOSED;
1203006ec67SBrian Somers     dl->dial_tries = -1;
1213006ec67SBrian Somers     dl->reconnect_tries = 0;
1223006ec67SBrian Somers     bundle_LinkClosed(dl->bundle, dl);
1233b0f8d2eSBrian Somers     if (!dl->bundle->CleaningUp)
124565e35e5SBrian Somers       datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
1253006ec67SBrian Somers   } else {
126aef795ccSBrian Somers     LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name);
1273006ec67SBrian Somers     dl->state = DATALINK_OPENING;
128abff9baeSBrian Somers     if (dl->dial_tries < 0) {
129565e35e5SBrian Somers       datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
130565e35e5SBrian Somers       dl->dial_tries = dl->cfg.dial.max;
131abff9baeSBrian Somers       dl->reconnect_tries--;
132abff9baeSBrian Somers     } else {
133f9545805SBrian Somers       if (dl->phone.next == NULL)
134565e35e5SBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
1353006ec67SBrian Somers       else
136565e35e5SBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
1373006ec67SBrian Somers     }
138abff9baeSBrian Somers   }
139abff9baeSBrian Somers }
1403006ec67SBrian Somers 
141f9545805SBrian Somers static const char *
142f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl)
143f9545805SBrian Somers {
144f9545805SBrian Somers   char *phone;
145f9545805SBrian Somers 
146f9545805SBrian Somers   if (dl->phone.alt == NULL) {
147f9545805SBrian Somers     if (dl->phone.next == NULL) {
148f9545805SBrian Somers       strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
149f9545805SBrian Somers       dl->phone.list[sizeof dl->phone.list - 1] = '\0';
150f9545805SBrian Somers       dl->phone.next = dl->phone.list;
151f9545805SBrian Somers     }
152f9545805SBrian Somers     dl->phone.alt = strsep(&dl->phone.next, ":");
153f9545805SBrian Somers   }
154f9545805SBrian Somers   phone = strsep(&dl->phone.alt, "|");
155f9545805SBrian Somers   dl->phone.chosen = *phone ? phone : "[NONE]";
156f9545805SBrian Somers   if (*phone)
157f9545805SBrian Somers     LogPrintf(LogPHASE, "Phone: %s\n", phone);
158f9545805SBrian Somers   return phone;
159f9545805SBrian Somers }
160f9545805SBrian Somers 
161c5a5a6caSBrian Somers static void
162c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl)
163c5a5a6caSBrian Somers {
164d345321bSBrian Somers   if (!dl->script.packetmode) {
165d345321bSBrian Somers     dl->dial_tries = -1;
166d345321bSBrian Somers     LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name);
167d345321bSBrian Somers     dl->state = DATALINK_READY;
168d345321bSBrian Somers   } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
169c5a5a6caSBrian Somers     dl->dial_tries = 0;
170c5a5a6caSBrian Somers     LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n");
171c5a5a6caSBrian Somers     if (dl->script.run) {
172c5a5a6caSBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
173c5a5a6caSBrian Somers       dl->state = DATALINK_HANGUP;
174c5a5a6caSBrian Somers       modem_Offline(dl->physical);
175f9545805SBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
176030e4ebbSBrian Somers     } else {
177030e4ebbSBrian Somers       if (dl->physical->type == PHYS_DEDICATED)
178030e4ebbSBrian Somers         /* force a redial timeout */
179030e4ebbSBrian Somers         modem_Close(dl->physical);
180c5a5a6caSBrian Somers       datalink_HangupDone(dl);
181030e4ebbSBrian Somers     }
182c5a5a6caSBrian Somers   } else {
183c7cc5030SBrian Somers     dl->dial_tries = -1;
184c7cc5030SBrian Somers 
185643f4904SBrian Somers     hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp);
1863b0f8d2eSBrian Somers     async_Init(&dl->physical->async);
1873b0f8d2eSBrian Somers 
188cd9647a1SBrian Somers     lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
189cd9647a1SBrian Somers               0 : dl->physical->link.lcp.cfg.openmode);
1903b0f8d2eSBrian Somers     ccp_Setup(&dl->physical->link.ccp);
191503a7782SBrian Somers 
192e2ebb036SBrian Somers     LogPrintf(LogPHASE, "%s: Entering LCP state\n", dl->name);
193e2ebb036SBrian Somers     dl->state = DATALINK_LCP;
1943b0f8d2eSBrian Somers     FsmUp(&dl->physical->link.lcp.fsm);
1953b0f8d2eSBrian Somers     FsmOpen(&dl->physical->link.lcp.fsm);
196c5a5a6caSBrian Somers   }
197c5a5a6caSBrian Somers }
198c5a5a6caSBrian Somers 
1993006ec67SBrian Somers static int
2003006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
2013006ec67SBrian Somers                    int *n)
2023006ec67SBrian Somers {
2033006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
2043006ec67SBrian Somers   int result;
2053006ec67SBrian Somers 
206310c3babSBrian Somers   result = 0;
2073006ec67SBrian Somers   switch (dl->state) {
2083006ec67SBrian Somers     case DATALINK_CLOSED:
209565e35e5SBrian Somers       if ((dl->physical->type & (PHYS_STDIN|PHYS_DEDICATED|PHYS_1OFF)) &&
210565e35e5SBrian Somers           !bundle_IsDead(dl->bundle))
211565e35e5SBrian Somers         /*
212565e35e5SBrian Somers          * Our first time in - DEDICATED never comes down, and STDIN & 1OFF
213565e35e5SBrian Somers          * get deleted when they enter DATALINK_CLOSED.  Go to
214565e35e5SBrian Somers          * DATALINK_OPENING via datalink_Up() and fall through.
215565e35e5SBrian Somers          */
216565e35e5SBrian Somers         datalink_Up(dl, 1, 1);
217565e35e5SBrian Somers       else
218310c3babSBrian Somers         break;
219565e35e5SBrian Somers       /* fall through */
2203006ec67SBrian Somers 
2213006ec67SBrian Somers     case DATALINK_OPENING:
2223006ec67SBrian Somers       if (dl->dial_timer.state != TIMER_RUNNING) {
2233006ec67SBrian Somers         if (--dl->dial_tries < 0)
2243006ec67SBrian Somers           dl->dial_tries = 0;
2253006ec67SBrian Somers         if (modem_Open(dl->physical, dl->bundle) >= 0) {
226c5a5a6caSBrian Somers           if (dl->script.run) {
2273006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name);
2283006ec67SBrian Somers             dl->state = DATALINK_DIAL;
229f9545805SBrian Somers             chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
230f9545805SBrian Somers                       datalink_ChoosePhoneNumber(dl));
231565e35e5SBrian Somers             if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) &&
232565e35e5SBrian Somers                 dl->cfg.dial.max)
2333006ec67SBrian Somers               LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n",
234565e35e5SBrian Somers                         dl->name, dl->cfg.dial.max - dl->dial_tries,
235565e35e5SBrian Somers                         dl->cfg.dial.max);
2361342caedSBrian Somers             return datalink_UpdateSet(d, r, w, e, n);
237c5a5a6caSBrian Somers           } else
238c5a5a6caSBrian Somers             datalink_LoginDone(dl);
2393006ec67SBrian Somers         } else {
240565e35e5SBrian Somers           if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) &&
241565e35e5SBrian Somers               dl->cfg.dial.max)
2423006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
243565e35e5SBrian Somers                       dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max);
2443006ec67SBrian Somers           else
2453006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem\n");
2463006ec67SBrian Somers 
2473b0f8d2eSBrian Somers           if (dl->bundle->CleaningUp ||
248565e35e5SBrian Somers               (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) &&
249565e35e5SBrian Somers                dl->cfg.dial.max && dl->dial_tries == 0)) {
2503006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
2513006ec67SBrian Somers             dl->state = DATALINK_CLOSED;
2523006ec67SBrian Somers             dl->reconnect_tries = 0;
2533006ec67SBrian Somers             dl->dial_tries = -1;
2545b8b8060SBrian Somers             bundle_LinkClosed(dl->bundle, dl);
255c5a5a6caSBrian Somers           }
2563b0f8d2eSBrian Somers           if (!dl->bundle->CleaningUp)
257565e35e5SBrian Somers             datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
2583006ec67SBrian Somers         }
2593006ec67SBrian Somers       }
260310c3babSBrian Somers       break;
2613006ec67SBrian Somers 
2623006ec67SBrian Somers     case DATALINK_HANGUP:
2633006ec67SBrian Somers     case DATALINK_DIAL:
2643006ec67SBrian Somers     case DATALINK_LOGIN:
2653006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
2663006ec67SBrian Somers       switch (dl->chat.state) {
2673006ec67SBrian Somers         case CHAT_DONE:
2683006ec67SBrian Somers           /* script succeeded */
26939d94652SBrian Somers           chat_Destroy(&dl->chat);
2703006ec67SBrian Somers           switch(dl->state) {
2713006ec67SBrian Somers             case DATALINK_HANGUP:
2723006ec67SBrian Somers               datalink_HangupDone(dl);
2733006ec67SBrian Somers               break;
2743006ec67SBrian Somers             case DATALINK_DIAL:
2753006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name);
2763006ec67SBrian Somers               dl->state = DATALINK_LOGIN;
277f9545805SBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
2781342caedSBrian Somers               return datalink_UpdateSet(d, r, w, e, n);
2793006ec67SBrian Somers             case DATALINK_LOGIN:
280c5a5a6caSBrian Somers               datalink_LoginDone(dl);
2813006ec67SBrian Somers               break;
2823006ec67SBrian Somers           }
2833006ec67SBrian Somers           break;
2843006ec67SBrian Somers         case CHAT_FAILED:
2853006ec67SBrian Somers           /* Going down - script failed */
2863006ec67SBrian Somers           LogPrintf(LogWARN, "Chat script failed\n");
28739d94652SBrian Somers           chat_Destroy(&dl->chat);
2883006ec67SBrian Somers           switch(dl->state) {
2893006ec67SBrian Somers             case DATALINK_HANGUP:
2903006ec67SBrian Somers               datalink_HangupDone(dl);
2913006ec67SBrian Somers               break;
2923006ec67SBrian Somers             case DATALINK_DIAL:
2933006ec67SBrian Somers             case DATALINK_LOGIN:
2943006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
2953006ec67SBrian Somers               dl->state = DATALINK_HANGUP;
2963006ec67SBrian Somers               modem_Offline(dl->physical);
297f9545805SBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
2981342caedSBrian Somers               return datalink_UpdateSet(d, r, w, e, n);
2993006ec67SBrian Somers           }
3003006ec67SBrian Somers           break;
3013006ec67SBrian Somers       }
3023006ec67SBrian Somers       break;
303c7cc5030SBrian Somers 
304c7cc5030SBrian Somers     case DATALINK_READY:
305e2ebb036SBrian Somers     case DATALINK_LCP:
306e2ebb036SBrian Somers     case DATALINK_AUTH:
3073006ec67SBrian Somers     case DATALINK_OPEN:
3083006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
3093006ec67SBrian Somers       break;
3103006ec67SBrian Somers   }
3113006ec67SBrian Somers   return result;
3123006ec67SBrian Somers }
3133006ec67SBrian Somers 
3143006ec67SBrian Somers static int
3152f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset)
3163006ec67SBrian Somers {
3173006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
3183006ec67SBrian Somers 
3193006ec67SBrian Somers   switch (dl->state) {
3203006ec67SBrian Somers     case DATALINK_CLOSED:
321c7cc5030SBrian Somers     case DATALINK_OPENING:
3223006ec67SBrian Somers       break;
323c7cc5030SBrian Somers 
3243006ec67SBrian Somers     case DATALINK_HANGUP:
3253006ec67SBrian Somers     case DATALINK_DIAL:
3263006ec67SBrian Somers     case DATALINK_LOGIN:
3273006ec67SBrian Somers       return descriptor_IsSet(&dl->chat.desc, fdset);
328c7cc5030SBrian Somers 
329c7cc5030SBrian Somers     case DATALINK_READY:
330e2ebb036SBrian Somers     case DATALINK_LCP:
331e2ebb036SBrian Somers     case DATALINK_AUTH:
3323006ec67SBrian Somers     case DATALINK_OPEN:
3333006ec67SBrian Somers       return descriptor_IsSet(&dl->physical->desc, fdset);
3343006ec67SBrian Somers   }
3353006ec67SBrian Somers   return 0;
3363006ec67SBrian Somers }
3373006ec67SBrian Somers 
3383006ec67SBrian Somers static void
3393006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
3403006ec67SBrian Somers {
3413006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
3423006ec67SBrian Somers 
3433006ec67SBrian Somers   switch (dl->state) {
3443006ec67SBrian Somers     case DATALINK_CLOSED:
345c7cc5030SBrian Somers     case DATALINK_OPENING:
3463006ec67SBrian Somers       break;
347c7cc5030SBrian Somers 
3483006ec67SBrian Somers     case DATALINK_HANGUP:
3493006ec67SBrian Somers     case DATALINK_DIAL:
3503006ec67SBrian Somers     case DATALINK_LOGIN:
3513006ec67SBrian Somers       descriptor_Read(&dl->chat.desc, bundle, fdset);
3523006ec67SBrian Somers       break;
353c7cc5030SBrian Somers 
354c7cc5030SBrian Somers     case DATALINK_READY:
355e2ebb036SBrian Somers     case DATALINK_LCP:
356e2ebb036SBrian Somers     case DATALINK_AUTH:
3573006ec67SBrian Somers     case DATALINK_OPEN:
3583006ec67SBrian Somers       descriptor_Read(&dl->physical->desc, bundle, fdset);
3593006ec67SBrian Somers       break;
3603006ec67SBrian Somers   }
3613006ec67SBrian Somers }
3623006ec67SBrian Somers 
3633006ec67SBrian Somers static void
364f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
3653006ec67SBrian Somers {
3663006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
3673006ec67SBrian Somers 
3683006ec67SBrian Somers   switch (dl->state) {
3693006ec67SBrian Somers     case DATALINK_CLOSED:
370c7cc5030SBrian Somers     case DATALINK_OPENING:
3713006ec67SBrian Somers       break;
372c7cc5030SBrian Somers 
3733006ec67SBrian Somers     case DATALINK_HANGUP:
3743006ec67SBrian Somers     case DATALINK_DIAL:
3753006ec67SBrian Somers     case DATALINK_LOGIN:
376f4768038SBrian Somers       descriptor_Write(&dl->chat.desc, bundle, fdset);
3773006ec67SBrian Somers       break;
378c7cc5030SBrian Somers 
379c7cc5030SBrian Somers     case DATALINK_READY:
380e2ebb036SBrian Somers     case DATALINK_LCP:
381e2ebb036SBrian Somers     case DATALINK_AUTH:
3823006ec67SBrian Somers     case DATALINK_OPEN:
383f4768038SBrian Somers       descriptor_Write(&dl->physical->desc, bundle, fdset);
3843006ec67SBrian Somers       break;
3853006ec67SBrian Somers   }
3863006ec67SBrian Somers }
3873006ec67SBrian Somers 
3886d666775SBrian Somers static void
389e2ebb036SBrian Somers datalink_ComeDown(struct datalink *dl, int stay)
390e2ebb036SBrian Somers {
391e2ebb036SBrian Somers   if (stay) {
392e2ebb036SBrian Somers     dl->dial_tries = -1;
393e2ebb036SBrian Somers     dl->reconnect_tries = 0;
394e2ebb036SBrian Somers   }
395e2ebb036SBrian Somers 
396e2ebb036SBrian Somers   if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
397e2ebb036SBrian Somers     modem_Offline(dl->physical);
398e2ebb036SBrian Somers     if (dl->script.run && dl->state != DATALINK_OPENING) {
399e2ebb036SBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
400e2ebb036SBrian Somers       dl->state = DATALINK_HANGUP;
401f9545805SBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
402e2ebb036SBrian Somers     } else
403e2ebb036SBrian Somers       datalink_HangupDone(dl);
404e2ebb036SBrian Somers   }
405e2ebb036SBrian Somers }
406e2ebb036SBrian Somers 
407e2ebb036SBrian Somers static void
4086d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp)
4096d666775SBrian Somers {
4106d666775SBrian Somers   /* The given FSM is about to start up ! */
4116d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
412a611cad6SBrian Somers 
41392e872e7SBrian Somers   if (fp->proto == PROTO_LCP)
414e2ebb036SBrian Somers     (*dl->parent->LayerStart)(dl->parent->object, fp);
415e2ebb036SBrian Somers }
4166d666775SBrian Somers 
4176d666775SBrian Somers static void
4186d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp)
4196d666775SBrian Somers {
4206d666775SBrian Somers   /* The given fsm is now up */
4216d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
4226d666775SBrian Somers 
42392e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
424643f4904SBrian Somers     datalink_GotAuthname(dl, "", 0);
4253b0f8d2eSBrian Somers     dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
4263b0f8d2eSBrian Somers     dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
4273b0f8d2eSBrian Somers     if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
4283b0f8d2eSBrian Somers       if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
4295563ebdeSBrian Somers         bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
430e2ebb036SBrian Somers       LogPrintf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
4313b0f8d2eSBrian Somers                 Auth2Nam(dl->physical->link.lcp.his_auth),
4323b0f8d2eSBrian Somers                 Auth2Nam(dl->physical->link.lcp.want_auth));
4333b0f8d2eSBrian Somers       if (dl->physical->link.lcp.his_auth == PROTO_PAP)
434e2ebb036SBrian Somers         StartAuthChallenge(&dl->pap, dl->physical, SendPapChallenge);
4353b0f8d2eSBrian Somers       if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
436e2ebb036SBrian Somers         StartAuthChallenge(&dl->chap.auth, dl->physical, SendChapChallenge);
437e2ebb036SBrian Somers     } else
438e2ebb036SBrian Somers       datalink_AuthOk(dl);
439e2ebb036SBrian Somers   }
440e2ebb036SBrian Somers }
441e2ebb036SBrian Somers 
442e2ebb036SBrian Somers void
443643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len)
444643f4904SBrian Somers {
445643f4904SBrian Somers   if (len >= sizeof dl->peer.authname)
446643f4904SBrian Somers     len = sizeof dl->peer.authname - 1;
447643f4904SBrian Somers   strncpy(dl->peer.authname, name, len);
448643f4904SBrian Somers   dl->peer.authname[len] = '\0';
449643f4904SBrian Somers }
450643f4904SBrian Somers 
451643f4904SBrian Somers void
452e2ebb036SBrian Somers datalink_AuthOk(struct datalink *dl)
453e2ebb036SBrian Somers {
4543b0f8d2eSBrian Somers   /* XXX: Connect to another ppp instance HERE */
4553b0f8d2eSBrian Somers 
456dbf60d74SBrian Somers   if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) {
457643f4904SBrian Somers     if (!mp_Up(&dl->bundle->ncp.mp, &dl->peer,
45849052c95SBrian Somers                dl->physical->link.lcp.want_mrru,
45949052c95SBrian Somers                dl->physical->link.lcp.his_mrru,
46049052c95SBrian Somers                dl->physical->link.lcp.want_shortseq,
46149052c95SBrian Somers                dl->physical->link.lcp.his_shortseq)) {
46249052c95SBrian Somers       datalink_AuthNotOk(dl);
46349052c95SBrian Somers       return;
46449052c95SBrian Somers     }
46549052c95SBrian Somers   } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) {
46649052c95SBrian Somers     LogPrintf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name);
46749052c95SBrian Somers     datalink_AuthNotOk(dl);
46849052c95SBrian Somers     return;
469ce828a6eSBrian Somers   } else
470ce828a6eSBrian Somers     ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link);
47149052c95SBrian Somers 
472643f4904SBrian Somers   AuthSelect(dl->bundle, dl->peer.authname, dl->physical);
4733b0f8d2eSBrian Somers   FsmUp(&dl->physical->link.ccp.fsm);
4743b0f8d2eSBrian Somers   FsmOpen(&dl->physical->link.ccp.fsm);
475e2ebb036SBrian Somers   dl->state = DATALINK_OPEN;
4763b0f8d2eSBrian Somers   bundle_NewPhase(dl->bundle, PHASE_NETWORK);
4773b0f8d2eSBrian Somers   (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
4786d666775SBrian Somers }
479e2ebb036SBrian Somers 
480e2ebb036SBrian Somers void
481e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl)
482e2ebb036SBrian Somers {
483e2ebb036SBrian Somers   dl->state = DATALINK_LCP;
4843b0f8d2eSBrian Somers   FsmClose(&dl->physical->link.lcp.fsm);
4856d666775SBrian Somers }
4866d666775SBrian Somers 
4876d666775SBrian Somers static void
4886d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp)
4896d666775SBrian Somers {
4906d666775SBrian Somers   /* The given FSM has been told to come down */
4916d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
492a611cad6SBrian Somers 
49392e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
494e2ebb036SBrian Somers     switch (dl->state) {
495e2ebb036SBrian Somers       case DATALINK_OPEN:
496643f4904SBrian Somers         peerid_Init(&dl->peer);
4973b0f8d2eSBrian Somers         FsmDown(&dl->physical->link.ccp.fsm);
4983b0f8d2eSBrian Somers         FsmClose(&dl->physical->link.ccp.fsm);
499e2ebb036SBrian Somers         (*dl->parent->LayerDown)(dl->parent->object, fp);
500e2ebb036SBrian Somers         /* fall through */
501e2ebb036SBrian Somers 
502e2ebb036SBrian Somers       case DATALINK_AUTH:
503e2ebb036SBrian Somers         StopTimer(&dl->pap.authtimer);
504e2ebb036SBrian Somers         StopTimer(&dl->chap.auth.authtimer);
5056d666775SBrian Somers     }
506e2ebb036SBrian Somers     dl->state = DATALINK_LCP;
507e2ebb036SBrian Somers   }
5086d666775SBrian Somers }
5096d666775SBrian Somers 
5106d666775SBrian Somers static void
5116d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp)
5126d666775SBrian Somers {
5136d666775SBrian Somers   /* The given fsm is now down */
5146d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
5156d666775SBrian Somers 
51692e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
51792e872e7SBrian Somers     FsmDown(fp);	/* Bring us to INITIAL or STARTING */
5186d666775SBrian Somers     (*dl->parent->LayerFinish)(dl->parent->object, fp);
519e2ebb036SBrian Somers     datalink_ComeDown(dl, 0);
5206d666775SBrian Somers   }
5216d666775SBrian Somers }
5226d666775SBrian Somers 
5233006ec67SBrian Somers struct datalink *
5246d666775SBrian Somers datalink_Create(const char *name, struct bundle *bundle,
525565e35e5SBrian Somers                 const struct fsm_parent *parent, int type)
5263006ec67SBrian Somers {
5273006ec67SBrian Somers   struct datalink *dl;
5283006ec67SBrian Somers 
5293006ec67SBrian Somers   dl = (struct datalink *)malloc(sizeof(struct datalink));
5303006ec67SBrian Somers   if (dl == NULL)
5313006ec67SBrian Somers     return dl;
5323006ec67SBrian Somers 
5333006ec67SBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
5343006ec67SBrian Somers   dl->desc.next = NULL;
5353006ec67SBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
5363006ec67SBrian Somers   dl->desc.IsSet = datalink_IsSet;
5373006ec67SBrian Somers   dl->desc.Read = datalink_Read;
5383006ec67SBrian Somers   dl->desc.Write = datalink_Write;
5395b8b8060SBrian Somers 
540e718d1d7SBrian Somers   dl->state = DATALINK_CLOSED;
541e718d1d7SBrian Somers 
54273a13b5cSBrian Somers   *dl->cfg.script.dial = '\0';
54373a13b5cSBrian Somers   *dl->cfg.script.login = '\0';
54473a13b5cSBrian Somers   *dl->cfg.script.hangup = '\0';
545f9545805SBrian Somers   *dl->cfg.phone.list = '\0';
546f9545805SBrian Somers   *dl->phone.list = '\0';
547f9545805SBrian Somers   dl->phone.next = NULL;
548f9545805SBrian Somers   dl->phone.alt = NULL;
549f9545805SBrian Somers   dl->phone.chosen = "N/A";
550c7cc5030SBrian Somers   dl->script.run = 1;
551c7cc5030SBrian Somers   dl->script.packetmode = 1;
5523b0f8d2eSBrian Somers   mp_linkInit(&dl->mp);
5535b8b8060SBrian Somers 
5543006ec67SBrian Somers   dl->bundle = bundle;
5553006ec67SBrian Somers   dl->next = NULL;
556e718d1d7SBrian Somers 
5573006ec67SBrian Somers   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
558e718d1d7SBrian Somers 
5593006ec67SBrian Somers   dl->dial_tries = 0;
560565e35e5SBrian Somers   dl->cfg.dial.max = 1;
561565e35e5SBrian Somers   dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
562565e35e5SBrian Somers   dl->cfg.dial.timeout = DIAL_TIMEOUT;
563e718d1d7SBrian Somers 
564abff9baeSBrian Somers   dl->reconnect_tries = 0;
565565e35e5SBrian Somers   dl->cfg.reconnect.max = 0;
566565e35e5SBrian Somers   dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
567abff9baeSBrian Somers 
5683006ec67SBrian Somers   dl->name = strdup(name);
569643f4904SBrian Somers   peerid_Init(&dl->peer);
5703b0f8d2eSBrian Somers   dl->parent = parent;
5713b0f8d2eSBrian Somers   dl->fsmp.LayerStart = datalink_LayerStart;
5723b0f8d2eSBrian Somers   dl->fsmp.LayerUp = datalink_LayerUp;
5733b0f8d2eSBrian Somers   dl->fsmp.LayerDown = datalink_LayerDown;
5743b0f8d2eSBrian Somers   dl->fsmp.LayerFinish = datalink_LayerFinish;
5753b0f8d2eSBrian Somers   dl->fsmp.object = dl;
5763b0f8d2eSBrian Somers 
5773b0f8d2eSBrian Somers   authinfo_Init(&dl->pap);
5783b0f8d2eSBrian Somers   authinfo_Init(&dl->chap.auth);
5793b0f8d2eSBrian Somers 
580565e35e5SBrian Somers   if ((dl->physical = modem_Create(dl, type)) == NULL) {
5813006ec67SBrian Somers     free(dl->name);
5823006ec67SBrian Somers     free(dl);
5833006ec67SBrian Somers     return NULL;
5843006ec67SBrian Somers   }
585f9545805SBrian Somers   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
5863006ec67SBrian Somers 
587c7cc5030SBrian Somers   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
5883006ec67SBrian Somers 
5893006ec67SBrian Somers   return dl;
5903006ec67SBrian Somers }
5913006ec67SBrian Somers 
5923006ec67SBrian Somers struct datalink *
593cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name)
594cd7bd93aSBrian Somers {
595cd7bd93aSBrian Somers   struct datalink *dl;
596cd7bd93aSBrian Somers 
597cd7bd93aSBrian Somers   dl = (struct datalink *)malloc(sizeof(struct datalink));
598cd7bd93aSBrian Somers   if (dl == NULL)
599cd7bd93aSBrian Somers     return dl;
600cd7bd93aSBrian Somers 
601cd7bd93aSBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
602cd7bd93aSBrian Somers   dl->desc.next = NULL;
603cd7bd93aSBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
604cd7bd93aSBrian Somers   dl->desc.IsSet = datalink_IsSet;
605cd7bd93aSBrian Somers   dl->desc.Read = datalink_Read;
606cd7bd93aSBrian Somers   dl->desc.Write = datalink_Write;
607cd7bd93aSBrian Somers 
608cd7bd93aSBrian Somers   dl->state = DATALINK_CLOSED;
609cd7bd93aSBrian Somers 
610cd7bd93aSBrian Somers   memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
611cd7bd93aSBrian Somers   mp_linkInit(&dl->mp);
612cd7bd93aSBrian Somers   *dl->phone.list = '\0';
613643f4904SBrian Somers   dl->phone.next = NULL;
614643f4904SBrian Somers   dl->phone.alt = NULL;
615643f4904SBrian Somers   dl->phone.chosen = "N/A";
616cd7bd93aSBrian Somers   dl->bundle = odl->bundle;
617cd7bd93aSBrian Somers   dl->next = NULL;
618cd7bd93aSBrian Somers   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
619cd7bd93aSBrian Somers   dl->dial_tries = 0;
620cd7bd93aSBrian Somers   dl->reconnect_tries = 0;
621cd7bd93aSBrian Somers   dl->name = strdup(name);
622643f4904SBrian Somers   peerid_Init(&dl->peer);
623cd7bd93aSBrian Somers   dl->parent = odl->parent;
624cd7bd93aSBrian Somers   memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
625643f4904SBrian Somers   dl->fsmp.object = dl;
626cd7bd93aSBrian Somers   authinfo_Init(&dl->pap);
627cd7bd93aSBrian Somers   dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry;
628cd7bd93aSBrian Somers 
629cd7bd93aSBrian Somers   authinfo_Init(&dl->chap.auth);
630cd7bd93aSBrian Somers   dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry;
631cd7bd93aSBrian Somers 
632565e35e5SBrian Somers   if ((dl->physical = modem_Create(dl, PHYS_MANUAL)) == NULL) {
633cd7bd93aSBrian Somers     free(dl->name);
634cd7bd93aSBrian Somers     free(dl);
635cd7bd93aSBrian Somers     return NULL;
636cd7bd93aSBrian Somers   }
637cd7bd93aSBrian Somers   memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
638cd7bd93aSBrian Somers   memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
639cd7bd93aSBrian Somers          sizeof dl->physical->link.lcp.cfg);
640cd7bd93aSBrian Somers   memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
641cd7bd93aSBrian Somers          sizeof dl->physical->link.ccp.cfg);
642cd7bd93aSBrian Somers   memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
643cd7bd93aSBrian Somers          sizeof dl->physical->async.cfg);
644cd7bd93aSBrian Somers 
645cd7bd93aSBrian Somers   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
646cd7bd93aSBrian Somers 
647cd7bd93aSBrian Somers   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
648cd7bd93aSBrian Somers 
649cd7bd93aSBrian Somers   return dl;
650cd7bd93aSBrian Somers }
651cd7bd93aSBrian Somers 
652cd7bd93aSBrian Somers struct datalink *
6533006ec67SBrian Somers datalink_Destroy(struct datalink *dl)
6543006ec67SBrian Somers {
6553006ec67SBrian Somers   struct datalink *result;
6563006ec67SBrian Somers 
65739d94652SBrian Somers   if (dl->state != DATALINK_CLOSED) {
658c7cc5030SBrian Somers     LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n",
659c7cc5030SBrian Somers               datalink_State(dl));
66039d94652SBrian Somers     switch (dl->state) {
66139d94652SBrian Somers       case DATALINK_HANGUP:
66239d94652SBrian Somers       case DATALINK_DIAL:
66339d94652SBrian Somers       case DATALINK_LOGIN:
66439d94652SBrian Somers         chat_Destroy(&dl->chat);	/* Gotta blat the timers ! */
66539d94652SBrian Somers         break;
66639d94652SBrian Somers     }
66739d94652SBrian Somers   }
6683006ec67SBrian Somers 
6693006ec67SBrian Somers   result = dl->next;
6703b0f8d2eSBrian Somers   modem_Destroy(dl->physical);
6713006ec67SBrian Somers   free(dl->name);
6723006ec67SBrian Somers   free(dl);
6733006ec67SBrian Somers 
6743006ec67SBrian Somers   return result;
6753006ec67SBrian Somers }
6763006ec67SBrian Somers 
6773006ec67SBrian Somers void
678c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode)
6793006ec67SBrian Somers {
680565e35e5SBrian Somers   if (dl->physical->type & (PHYS_STDIN|PHYS_DEDICATED))
681565e35e5SBrian Somers     /* Ignore scripts */
682565e35e5SBrian Somers     runscripts = 0;
683565e35e5SBrian Somers 
684c7cc5030SBrian Somers   switch (dl->state) {
685c7cc5030SBrian Somers     case DATALINK_CLOSED:
6863006ec67SBrian Somers       LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name);
6873b0f8d2eSBrian Somers       if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
6883b0f8d2eSBrian Somers           bundle_Phase(dl->bundle) == PHASE_TERMINATE)
6893b0f8d2eSBrian Somers         bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
6903006ec67SBrian Somers       dl->state = DATALINK_OPENING;
691565e35e5SBrian Somers       dl->reconnect_tries =
692565e35e5SBrian Somers         dl->physical->type == PHYS_STDIN ? 0 : dl->cfg.reconnect.max;
693565e35e5SBrian Somers       dl->dial_tries = dl->cfg.dial.max;
694c5a5a6caSBrian Somers       dl->script.run = runscripts;
695c5a5a6caSBrian Somers       dl->script.packetmode = packetmode;
696c7cc5030SBrian Somers       break;
697c7cc5030SBrian Somers 
698c7cc5030SBrian Somers     case DATALINK_OPENING:
699c7cc5030SBrian Somers       if (!dl->script.run && runscripts)
700c7cc5030SBrian Somers         dl->script.run = 1;
701c7cc5030SBrian Somers       /* fall through */
702c7cc5030SBrian Somers 
703c7cc5030SBrian Somers     case DATALINK_DIAL:
704c7cc5030SBrian Somers     case DATALINK_LOGIN:
705c7cc5030SBrian Somers     case DATALINK_READY:
706c7cc5030SBrian Somers       if (!dl->script.packetmode && packetmode) {
707c7cc5030SBrian Somers         dl->script.packetmode = 1;
708c7cc5030SBrian Somers         if (dl->state == DATALINK_READY)
709c7cc5030SBrian Somers           datalink_LoginDone(dl);
710c7cc5030SBrian Somers       }
711c7cc5030SBrian Somers       break;
7123006ec67SBrian Somers   }
7133006ec67SBrian Somers }
7143006ec67SBrian Somers 
7153006ec67SBrian Somers void
716c7cc5030SBrian Somers datalink_Close(struct datalink *dl, int stay)
717c7cc5030SBrian Somers {
718c7cc5030SBrian Somers   /* Please close */
719e2ebb036SBrian Somers   switch (dl->state) {
720e2ebb036SBrian Somers     case DATALINK_OPEN:
721643f4904SBrian Somers       peerid_Init(&dl->peer);
7223b0f8d2eSBrian Somers       FsmDown(&dl->physical->link.ccp.fsm);
7233b0f8d2eSBrian Somers       FsmClose(&dl->physical->link.ccp.fsm);
724e2ebb036SBrian Somers       /* fall through */
725e2ebb036SBrian Somers 
726e2ebb036SBrian Somers     case DATALINK_AUTH:
727e2ebb036SBrian Somers     case DATALINK_LCP:
7283b0f8d2eSBrian Somers       FsmClose(&dl->physical->link.lcp.fsm);
729c7cc5030SBrian Somers       if (stay) {
730c7cc5030SBrian Somers         dl->dial_tries = -1;
731c7cc5030SBrian Somers         dl->reconnect_tries = 0;
732c7cc5030SBrian Somers       }
733e2ebb036SBrian Somers       break;
734e2ebb036SBrian Somers 
735e2ebb036SBrian Somers     default:
736c7cc5030SBrian Somers       datalink_ComeDown(dl, stay);
737c7cc5030SBrian Somers   }
738e2ebb036SBrian Somers }
739c7cc5030SBrian Somers 
740c7cc5030SBrian Somers void
741c7cc5030SBrian Somers datalink_Down(struct datalink *dl, int stay)
742c7cc5030SBrian Somers {
743c7cc5030SBrian Somers   /* Carrier is lost */
744e2ebb036SBrian Somers   switch (dl->state) {
745e2ebb036SBrian Somers     case DATALINK_OPEN:
746643f4904SBrian Somers       peerid_Init(&dl->peer);
7473b0f8d2eSBrian Somers       FsmDown(&dl->physical->link.ccp.fsm);
7483b0f8d2eSBrian Somers       FsmClose(&dl->physical->link.ccp.fsm);
749e2ebb036SBrian Somers       /* fall through */
750e2ebb036SBrian Somers 
751e2ebb036SBrian Somers     case DATALINK_AUTH:
752e2ebb036SBrian Somers     case DATALINK_LCP:
7533b0f8d2eSBrian Somers       FsmDown(&dl->physical->link.lcp.fsm);
754c7cc5030SBrian Somers       if (stay)
7553b0f8d2eSBrian Somers         FsmClose(&dl->physical->link.lcp.fsm);
756c7cc5030SBrian Somers       else
7573b0f8d2eSBrian Somers         FsmOpen(&dl->physical->link.ccp.fsm);
758e2ebb036SBrian Somers       /* fall through */
759c7cc5030SBrian Somers 
760e2ebb036SBrian Somers     default:
761c7cc5030SBrian Somers       datalink_ComeDown(dl, stay);
762c7cc5030SBrian Somers   }
763e2ebb036SBrian Somers }
764c7cc5030SBrian Somers 
765c7cc5030SBrian Somers void
7663006ec67SBrian Somers datalink_StayDown(struct datalink *dl)
7673006ec67SBrian Somers {
7683006ec67SBrian Somers   dl->reconnect_tries = 0;
7693006ec67SBrian Somers }
770c7cc5030SBrian Somers 
771643f4904SBrian Somers int
772643f4904SBrian Somers datalink_Show(struct cmdargs const *arg)
773c7cc5030SBrian Somers {
774643f4904SBrian Somers   prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
775643f4904SBrian Somers   prompt_Printf(arg->prompt, " State:            %s\n",
776643f4904SBrian Somers                 datalink_State(arg->cx));
777643f4904SBrian Somers   prompt_Printf(arg->prompt, " CHAP Encryption:  %s\n",
778643f4904SBrian Somers                 arg->cx->chap.using_MSChap ? "MSChap" : "MD5" );
779643f4904SBrian Somers   prompt_Printf(arg->prompt, " Peer name:        ");
780643f4904SBrian Somers   if (*arg->cx->peer.authname)
781643f4904SBrian Somers     prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname);
782643f4904SBrian Somers   else if (arg->cx->state == DATALINK_OPEN)
783643f4904SBrian Somers     prompt_Printf(arg->prompt, "None requested\n");
784565e35e5SBrian Somers   else
785643f4904SBrian Somers     prompt_Printf(arg->prompt, "N/A\n");
786643f4904SBrian Somers   prompt_Printf(arg->prompt, " Discriminator:    %s\n",
787643f4904SBrian Somers                 mp_Enddisc(arg->cx->peer.enddisc.class,
788643f4904SBrian Somers                            arg->cx->peer.enddisc.address,
789643f4904SBrian Somers                            arg->cx->peer.enddisc.len));
790643f4904SBrian Somers 
791643f4904SBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
792643f4904SBrian Somers   prompt_Printf(arg->prompt, " Phone List:       %s\n",
793643f4904SBrian Somers                 arg->cx->cfg.phone.list);
794643f4904SBrian Somers   if (arg->cx->cfg.dial.max)
795643f4904SBrian Somers     prompt_Printf(arg->prompt, " Dial tries:       %d, delay ",
796643f4904SBrian Somers                   arg->cx->cfg.dial.max);
797565e35e5SBrian Somers   else
798643f4904SBrian Somers     prompt_Printf(arg->prompt, " Dial tries:       infinite, delay ");
799643f4904SBrian Somers   if (arg->cx->cfg.dial.next_timeout > 0)
800643f4904SBrian Somers     prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout);
801565e35e5SBrian Somers   else
802643f4904SBrian Somers     prompt_Printf(arg->prompt, "random/");
803643f4904SBrian Somers   if (arg->cx->cfg.dial.timeout > 0)
804643f4904SBrian Somers     prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout);
805565e35e5SBrian Somers   else
806643f4904SBrian Somers     prompt_Printf(arg->prompt, "random\n");
807643f4904SBrian Somers   prompt_Printf(arg->prompt, " Reconnect tries:  %d, delay ",
808643f4904SBrian Somers                 arg->cx->cfg.reconnect.max);
809643f4904SBrian Somers   if (arg->cx->cfg.reconnect.timeout > 0)
810643f4904SBrian Somers     prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout);
811643f4904SBrian Somers   else
812643f4904SBrian Somers     prompt_Printf(arg->prompt, "random\n");
813643f4904SBrian Somers   prompt_Printf(arg->prompt, " Dial Script:      %s\n",
814643f4904SBrian Somers                 arg->cx->cfg.script.dial);
815643f4904SBrian Somers   prompt_Printf(arg->prompt, " Login Script:     %s\n",
816643f4904SBrian Somers                 arg->cx->cfg.script.login);
817643f4904SBrian Somers   prompt_Printf(arg->prompt, " Hangup Script:    %s\n",
818643f4904SBrian Somers                 arg->cx->cfg.script.hangup);
819643f4904SBrian Somers   return 0;
820565e35e5SBrian Somers }
821565e35e5SBrian Somers 
822565e35e5SBrian Somers int
823565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg)
824565e35e5SBrian Somers {
82525092092SBrian Somers   if (arg->argc == arg->argn+2) {
82625092092SBrian Somers     arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]);
82725092092SBrian Somers     arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]);
828565e35e5SBrian Somers     return 0;
829565e35e5SBrian Somers   }
830565e35e5SBrian Somers   return -1;
831565e35e5SBrian Somers }
832565e35e5SBrian Somers 
833565e35e5SBrian Somers int
834565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg)
835565e35e5SBrian Somers {
836565e35e5SBrian Somers   int timeout;
837565e35e5SBrian Somers   int tries;
838565e35e5SBrian Somers   char *dot;
839565e35e5SBrian Somers 
84025092092SBrian Somers   if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) {
84125092092SBrian Somers     if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 &&
84225092092SBrian Somers 	(arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) {
843565e35e5SBrian Somers       arg->cx->cfg.dial.timeout = -1;
844565e35e5SBrian Somers       randinit();
845565e35e5SBrian Somers     } else {
84625092092SBrian Somers       timeout = atoi(arg->argv[arg->argn]);
847565e35e5SBrian Somers 
848565e35e5SBrian Somers       if (timeout >= 0)
849565e35e5SBrian Somers 	arg->cx->cfg.dial.timeout = timeout;
850565e35e5SBrian Somers       else {
851565e35e5SBrian Somers 	LogPrintf(LogWARN, "Invalid redial timeout\n");
852565e35e5SBrian Somers 	return -1;
853565e35e5SBrian Somers       }
854565e35e5SBrian Somers     }
855565e35e5SBrian Somers 
85625092092SBrian Somers     dot = strchr(arg->argv[arg->argn], '.');
857565e35e5SBrian Somers     if (dot) {
858565e35e5SBrian Somers       if (strcasecmp(++dot, "random") == 0) {
859565e35e5SBrian Somers 	arg->cx->cfg.dial.next_timeout = -1;
860565e35e5SBrian Somers 	randinit();
861565e35e5SBrian Somers       } else {
862565e35e5SBrian Somers 	timeout = atoi(dot);
863565e35e5SBrian Somers 	if (timeout >= 0)
864565e35e5SBrian Somers 	  arg->cx->cfg.dial.next_timeout = timeout;
865565e35e5SBrian Somers 	else {
866565e35e5SBrian Somers 	  LogPrintf(LogWARN, "Invalid next redial timeout\n");
867565e35e5SBrian Somers 	  return -1;
868565e35e5SBrian Somers 	}
869565e35e5SBrian Somers       }
870565e35e5SBrian Somers     } else
871565e35e5SBrian Somers       /* Default next timeout */
872565e35e5SBrian Somers       arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
873565e35e5SBrian Somers 
87425092092SBrian Somers     if (arg->argc == arg->argn+2) {
87525092092SBrian Somers       tries = atoi(arg->argv[arg->argn+1]);
876565e35e5SBrian Somers 
877565e35e5SBrian Somers       if (tries >= 0) {
878565e35e5SBrian Somers 	arg->cx->cfg.dial.max = tries;
879565e35e5SBrian Somers       } else {
880565e35e5SBrian Somers 	LogPrintf(LogWARN, "Invalid retry value\n");
881565e35e5SBrian Somers 	return 1;
882565e35e5SBrian Somers       }
883565e35e5SBrian Somers     }
884565e35e5SBrian Somers     return 0;
885565e35e5SBrian Somers   }
886565e35e5SBrian Somers   return -1;
887c7cc5030SBrian Somers }
888c7cc5030SBrian Somers 
889cdbbb6b5SBrian Somers static const char *states[] = {
890565e35e5SBrian Somers   "closed",
891565e35e5SBrian Somers   "opening",
892565e35e5SBrian Somers   "hangup",
893565e35e5SBrian Somers   "dial",
894565e35e5SBrian Somers   "login",
895565e35e5SBrian Somers   "ready",
896565e35e5SBrian Somers   "lcp",
897565e35e5SBrian Somers   "auth",
898565e35e5SBrian Somers   "open"
899c7cc5030SBrian Somers };
900c7cc5030SBrian Somers 
901643f4904SBrian Somers const char *
902c7cc5030SBrian Somers datalink_State(struct datalink *dl)
903c7cc5030SBrian Somers {
904c7cc5030SBrian Somers   if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
905c7cc5030SBrian Somers     return "unknown";
906c7cc5030SBrian Somers   return states[dl->state];
907c7cc5030SBrian Somers }
908