xref: /freebsd/usr.sbin/ppp/datalink.c (revision 5ca5389a)
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  *
265ca5389aSBrian Somers  *	$Id: datalink.c,v 1.1.2.22 1998/03/13 21:07:30 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"
48879ed6faSBrian Somers #include "lqr.h"
493006ec67SBrian Somers #include "hdlc.h"
503006ec67SBrian Somers #include "async.h"
513006ec67SBrian Somers #include "throughput.h"
523006ec67SBrian Somers #include "link.h"
533006ec67SBrian Somers #include "physical.h"
545828db6dSBrian Somers #include "iplist.h"
555828db6dSBrian Somers #include "ipcp.h"
565ca5389aSBrian Somers #include "filter.h"
573006ec67SBrian Somers #include "bundle.h"
583006ec67SBrian Somers #include "chat.h"
593006ec67SBrian Somers #include "ccp.h"
60e2ebb036SBrian Somers #include "auth.h"
613006ec67SBrian Somers #include "main.h"
623006ec67SBrian Somers #include "modem.h"
63c7cc5030SBrian Somers #include "prompt.h"
64e2ebb036SBrian Somers #include "lcpproto.h"
65e2ebb036SBrian Somers #include "pap.h"
66e2ebb036SBrian Somers #include "chap.h"
67e2ebb036SBrian Somers #include "datalink.h"
68c7cc5030SBrian Somers 
69c7cc5030SBrian Somers static const char *datalink_State(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     dl->dial_timer.state = TIMER_STOPPED;
883006ec67SBrian Somers     if (Timeout > 0)
893006ec67SBrian Somers       dl->dial_timer.load = Timeout * SECTICKS;
903006ec67SBrian Somers     else
91e718d1d7SBrian Somers       dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
923006ec67SBrian Somers     dl->dial_timer.func = datalink_OpenTimeout;
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 {
1043006ec67SBrian Somers   modem_Close(dl->physical);
105f9545805SBrian Somers   dl->phone.chosen = "[N/A]";
1063006ec67SBrian Somers 
1073006ec67SBrian Somers   if (!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) {
1083006ec67SBrian Somers     LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
1093006ec67SBrian Somers     dl->state = DATALINK_CLOSED;
1103006ec67SBrian Somers     dl->dial_tries = -1;
1113006ec67SBrian Somers     dl->reconnect_tries = 0;
1123006ec67SBrian Somers     bundle_LinkClosed(dl->bundle, dl);
11373a13b5cSBrian Somers     datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
1143006ec67SBrian Somers   } else {
115aef795ccSBrian Somers     LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name);
1163006ec67SBrian Somers     dl->state = DATALINK_OPENING;
117abff9baeSBrian Somers     if (dl->dial_tries < 0) {
11873a13b5cSBrian Somers       datalink_StartDialTimer(dl, dl->cfg.reconnect_timeout);
11973a13b5cSBrian Somers       dl->dial_tries = dl->cfg.max_dial;
120abff9baeSBrian Somers       dl->reconnect_tries--;
121abff9baeSBrian Somers     } else {
122abff9baeSBrian Somers       dl->dial_tries--;
123f9545805SBrian Somers       if (dl->phone.next == NULL)
12473a13b5cSBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
1253006ec67SBrian Somers       else
12673a13b5cSBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial_next_timeout);
1273006ec67SBrian Somers     }
128abff9baeSBrian Somers   }
129abff9baeSBrian Somers }
1303006ec67SBrian Somers 
131f9545805SBrian Somers static const char *
132f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl)
133f9545805SBrian Somers {
134f9545805SBrian Somers   char *phone;
135f9545805SBrian Somers 
136f9545805SBrian Somers   if (dl->phone.alt == NULL) {
137f9545805SBrian Somers     if (dl->phone.next == NULL) {
138f9545805SBrian Somers       strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
139f9545805SBrian Somers       dl->phone.list[sizeof dl->phone.list - 1] = '\0';
140f9545805SBrian Somers       dl->phone.next = dl->phone.list;
141f9545805SBrian Somers     }
142f9545805SBrian Somers     dl->phone.alt = strsep(&dl->phone.next, ":");
143f9545805SBrian Somers   }
144f9545805SBrian Somers   phone = strsep(&dl->phone.alt, "|");
145f9545805SBrian Somers   dl->phone.chosen = *phone ? phone : "[NONE]";
146f9545805SBrian Somers   if (*phone)
147f9545805SBrian Somers     LogPrintf(LogPHASE, "Phone: %s\n", phone);
148f9545805SBrian Somers   return phone;
149f9545805SBrian Somers }
150f9545805SBrian Somers 
151c5a5a6caSBrian Somers static void
152c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl)
153c5a5a6caSBrian Somers {
154d345321bSBrian Somers   if (!dl->script.packetmode) {
155d345321bSBrian Somers     dl->dial_tries = -1;
156d345321bSBrian Somers     LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name);
157d345321bSBrian Somers     dl->state = DATALINK_READY;
158d345321bSBrian Somers   } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
159c5a5a6caSBrian Somers     dl->dial_tries = 0;
160c5a5a6caSBrian Somers     LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n");
161c5a5a6caSBrian Somers     if (dl->script.run) {
162c5a5a6caSBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
163c5a5a6caSBrian Somers       dl->state = DATALINK_HANGUP;
164c5a5a6caSBrian Somers       modem_Offline(dl->physical);
165f9545805SBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
166c5a5a6caSBrian Somers     } else
167c5a5a6caSBrian Somers       datalink_HangupDone(dl);
168c5a5a6caSBrian Somers   } else {
169c7cc5030SBrian Somers     dl->dial_tries = -1;
170c7cc5030SBrian Somers 
171a611cad6SBrian Somers     lcp_Setup(&dl->lcp, dl->state == DATALINK_READY ? 0 : VarOpenMode);
172f4768038SBrian Somers     ccp_Setup(&dl->ccp);
173503a7782SBrian Somers 
174e2ebb036SBrian Somers     LogPrintf(LogPHASE, "%s: Entering LCP state\n", dl->name);
175e2ebb036SBrian Somers     dl->state = DATALINK_LCP;
176a611cad6SBrian Somers     FsmUp(&dl->lcp.fsm);
177a611cad6SBrian Somers     FsmOpen(&dl->lcp.fsm);
178c5a5a6caSBrian Somers   }
179c5a5a6caSBrian Somers }
180c5a5a6caSBrian Somers 
1813006ec67SBrian Somers static int
1823006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
1833006ec67SBrian Somers                    int *n)
1843006ec67SBrian Somers {
1853006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
1863006ec67SBrian Somers   int result;
1873006ec67SBrian Somers 
188310c3babSBrian Somers   result = 0;
1893006ec67SBrian Somers   switch (dl->state) {
1903006ec67SBrian Somers     case DATALINK_CLOSED:
191310c3babSBrian Somers       break;
1923006ec67SBrian Somers 
1933006ec67SBrian Somers     case DATALINK_OPENING:
1943006ec67SBrian Somers       if (dl->dial_timer.state != TIMER_RUNNING) {
1953006ec67SBrian Somers         if (--dl->dial_tries < 0)
1963006ec67SBrian Somers           dl->dial_tries = 0;
1973006ec67SBrian Somers         if (modem_Open(dl->physical, dl->bundle) >= 0) {
198c5a5a6caSBrian Somers           if (dl->script.run) {
1993006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name);
2003006ec67SBrian Somers             dl->state = DATALINK_DIAL;
201f9545805SBrian Somers             chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
202f9545805SBrian Somers                       datalink_ChoosePhoneNumber(dl));
20373a13b5cSBrian Somers             if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
2043006ec67SBrian Somers               LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n",
20573a13b5cSBrian Somers                         dl->name, dl->cfg.max_dial - dl->dial_tries,
20673a13b5cSBrian Somers                         dl->cfg.max_dial);
207c5a5a6caSBrian Somers           } else
208c5a5a6caSBrian Somers             datalink_LoginDone(dl);
2093006ec67SBrian Somers         } else {
21073a13b5cSBrian Somers           if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
2113006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
21273a13b5cSBrian Somers                       dl->cfg.max_dial - dl->dial_tries, dl->cfg.max_dial);
2133006ec67SBrian Somers           else
2143006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem\n");
2153006ec67SBrian Somers 
21673a13b5cSBrian Somers           if (!(mode & MODE_DDIAL) && dl->cfg.max_dial && dl->dial_tries == 0) {
2173006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
2183006ec67SBrian Somers             dl->state = DATALINK_CLOSED;
2193006ec67SBrian Somers             dl->reconnect_tries = 0;
2203006ec67SBrian Somers             dl->dial_tries = -1;
2215b8b8060SBrian Somers             bundle_LinkClosed(dl->bundle, dl);
222c5a5a6caSBrian Somers           }
22373a13b5cSBrian Somers           datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
2243006ec67SBrian Somers         }
2253006ec67SBrian Somers       }
226310c3babSBrian Somers       break;
2273006ec67SBrian Somers 
2283006ec67SBrian Somers     case DATALINK_HANGUP:
2293006ec67SBrian Somers     case DATALINK_DIAL:
2303006ec67SBrian Somers     case DATALINK_LOGIN:
2313006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
2323006ec67SBrian Somers       switch (dl->chat.state) {
2333006ec67SBrian Somers         case CHAT_DONE:
2343006ec67SBrian Somers           /* script succeeded */
2353006ec67SBrian Somers           switch(dl->state) {
2363006ec67SBrian Somers             case DATALINK_HANGUP:
2373006ec67SBrian Somers               datalink_HangupDone(dl);
2383006ec67SBrian Somers               break;
2393006ec67SBrian Somers             case DATALINK_DIAL:
2403006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name);
2413006ec67SBrian Somers               dl->state = DATALINK_LOGIN;
242f9545805SBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
2433006ec67SBrian Somers               break;
2443006ec67SBrian Somers             case DATALINK_LOGIN:
245c5a5a6caSBrian Somers               datalink_LoginDone(dl);
2463006ec67SBrian Somers               break;
2473006ec67SBrian Somers           }
2483006ec67SBrian Somers           break;
2493006ec67SBrian Somers         case CHAT_FAILED:
2503006ec67SBrian Somers           /* Going down - script failed */
2513006ec67SBrian Somers           LogPrintf(LogWARN, "Chat script failed\n");
2523006ec67SBrian Somers           switch(dl->state) {
2533006ec67SBrian Somers             case DATALINK_HANGUP:
2543006ec67SBrian Somers               datalink_HangupDone(dl);
2553006ec67SBrian Somers               break;
2563006ec67SBrian Somers             case DATALINK_DIAL:
2573006ec67SBrian Somers             case DATALINK_LOGIN:
2583006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
2593006ec67SBrian Somers               dl->state = DATALINK_HANGUP;
2603006ec67SBrian Somers               modem_Offline(dl->physical);
261f9545805SBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
2623006ec67SBrian Somers               break;
2633006ec67SBrian Somers           }
2643006ec67SBrian Somers           break;
2653006ec67SBrian Somers       }
2663006ec67SBrian Somers       break;
267c7cc5030SBrian Somers 
268c7cc5030SBrian Somers     case DATALINK_READY:
269e2ebb036SBrian Somers     case DATALINK_LCP:
270e2ebb036SBrian Somers     case DATALINK_AUTH:
2713006ec67SBrian Somers     case DATALINK_OPEN:
2723006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
2733006ec67SBrian Somers       break;
2743006ec67SBrian Somers   }
2753006ec67SBrian Somers   return result;
2763006ec67SBrian Somers }
2773006ec67SBrian Somers 
2783006ec67SBrian Somers static int
2793006ec67SBrian Somers datalink_IsSet(struct descriptor *d, fd_set *fdset)
2803006ec67SBrian Somers {
2813006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
2823006ec67SBrian Somers 
2833006ec67SBrian Somers   switch (dl->state) {
2843006ec67SBrian Somers     case DATALINK_CLOSED:
285c7cc5030SBrian Somers     case DATALINK_OPENING:
2863006ec67SBrian Somers       break;
287c7cc5030SBrian Somers 
2883006ec67SBrian Somers     case DATALINK_HANGUP:
2893006ec67SBrian Somers     case DATALINK_DIAL:
2903006ec67SBrian Somers     case DATALINK_LOGIN:
2913006ec67SBrian Somers       return descriptor_IsSet(&dl->chat.desc, fdset);
292c7cc5030SBrian Somers 
293c7cc5030SBrian Somers     case DATALINK_READY:
294e2ebb036SBrian Somers     case DATALINK_LCP:
295e2ebb036SBrian Somers     case DATALINK_AUTH:
2963006ec67SBrian Somers     case DATALINK_OPEN:
2973006ec67SBrian Somers       return descriptor_IsSet(&dl->physical->desc, fdset);
2983006ec67SBrian Somers   }
2993006ec67SBrian Somers   return 0;
3003006ec67SBrian Somers }
3013006ec67SBrian Somers 
3023006ec67SBrian Somers static void
3033006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
3043006ec67SBrian Somers {
3053006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
3063006ec67SBrian Somers 
3073006ec67SBrian Somers   switch (dl->state) {
3083006ec67SBrian Somers     case DATALINK_CLOSED:
309c7cc5030SBrian Somers     case DATALINK_OPENING:
3103006ec67SBrian Somers       break;
311c7cc5030SBrian Somers 
3123006ec67SBrian Somers     case DATALINK_HANGUP:
3133006ec67SBrian Somers     case DATALINK_DIAL:
3143006ec67SBrian Somers     case DATALINK_LOGIN:
3153006ec67SBrian Somers       descriptor_Read(&dl->chat.desc, bundle, fdset);
3163006ec67SBrian Somers       break;
317c7cc5030SBrian Somers 
318c7cc5030SBrian Somers     case DATALINK_READY:
319e2ebb036SBrian Somers     case DATALINK_LCP:
320e2ebb036SBrian Somers     case DATALINK_AUTH:
3213006ec67SBrian Somers     case DATALINK_OPEN:
3223006ec67SBrian Somers       descriptor_Read(&dl->physical->desc, bundle, fdset);
3233006ec67SBrian Somers       break;
3243006ec67SBrian Somers   }
3253006ec67SBrian Somers }
3263006ec67SBrian Somers 
3273006ec67SBrian Somers static void
328f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
3293006ec67SBrian Somers {
3303006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
3313006ec67SBrian Somers 
3323006ec67SBrian Somers   switch (dl->state) {
3333006ec67SBrian Somers     case DATALINK_CLOSED:
334c7cc5030SBrian Somers     case DATALINK_OPENING:
3353006ec67SBrian Somers       break;
336c7cc5030SBrian Somers 
3373006ec67SBrian Somers     case DATALINK_HANGUP:
3383006ec67SBrian Somers     case DATALINK_DIAL:
3393006ec67SBrian Somers     case DATALINK_LOGIN:
340f4768038SBrian Somers       descriptor_Write(&dl->chat.desc, bundle, fdset);
3413006ec67SBrian Somers       break;
342c7cc5030SBrian Somers 
343c7cc5030SBrian Somers     case DATALINK_READY:
344e2ebb036SBrian Somers     case DATALINK_LCP:
345e2ebb036SBrian Somers     case DATALINK_AUTH:
3463006ec67SBrian Somers     case DATALINK_OPEN:
347f4768038SBrian Somers       descriptor_Write(&dl->physical->desc, bundle, fdset);
3483006ec67SBrian Somers       break;
3493006ec67SBrian Somers   }
3503006ec67SBrian Somers }
3513006ec67SBrian Somers 
3526d666775SBrian Somers static void
353e2ebb036SBrian Somers datalink_ComeDown(struct datalink *dl, int stay)
354e2ebb036SBrian Somers {
355e2ebb036SBrian Somers   if (stay) {
356e2ebb036SBrian Somers     dl->dial_tries = -1;
357e2ebb036SBrian Somers     dl->reconnect_tries = 0;
358e2ebb036SBrian Somers   }
359e2ebb036SBrian Somers 
360e2ebb036SBrian Somers   if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
361e2ebb036SBrian Somers     modem_Offline(dl->physical);
362e2ebb036SBrian Somers     if (dl->script.run && dl->state != DATALINK_OPENING) {
363e2ebb036SBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
364e2ebb036SBrian Somers       dl->state = DATALINK_HANGUP;
365f9545805SBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
366e2ebb036SBrian Somers     } else
367e2ebb036SBrian Somers       datalink_HangupDone(dl);
368e2ebb036SBrian Somers   }
369e2ebb036SBrian Somers }
370e2ebb036SBrian Somers 
371e2ebb036SBrian Somers static void
3726d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp)
3736d666775SBrian Somers {
3746d666775SBrian Somers   /* The given FSM is about to start up ! */
3756d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
376a611cad6SBrian Somers 
377a611cad6SBrian Somers   if (fp == &dl->lcp.fsm)
378e2ebb036SBrian Somers     (*dl->parent->LayerStart)(dl->parent->object, fp);
379e2ebb036SBrian Somers }
3806d666775SBrian Somers 
3816d666775SBrian Somers static void
3826d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp)
3836d666775SBrian Somers {
3846d666775SBrian Somers   /* The given fsm is now up */
3856d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
3866d666775SBrian Somers 
387a611cad6SBrian Somers   if (fp == &dl->lcp.fsm) {
388a611cad6SBrian Somers     dl->lcp.auth_ineed = dl->lcp.want_auth;
389a611cad6SBrian Somers     dl->lcp.auth_iwait = dl->lcp.his_auth;
390a611cad6SBrian Somers     if (dl->lcp.his_auth || dl->lcp.want_auth) {
391e2ebb036SBrian Somers       if (dl->bundle->phase == PHASE_DEAD ||
392e2ebb036SBrian Somers           dl->bundle->phase == PHASE_ESTABLISH)
3935563ebdeSBrian Somers         bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
394e2ebb036SBrian Somers       LogPrintf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
395a611cad6SBrian Somers                 Auth2Nam(dl->lcp.his_auth), Auth2Nam(dl->lcp.want_auth));
396a611cad6SBrian Somers       if (dl->lcp.his_auth == PROTO_PAP)
397e2ebb036SBrian Somers         StartAuthChallenge(&dl->pap, dl->physical, SendPapChallenge);
398a611cad6SBrian Somers       if (dl->lcp.want_auth == PROTO_CHAP)
399e2ebb036SBrian Somers         StartAuthChallenge(&dl->chap.auth, dl->physical, SendChapChallenge);
400e2ebb036SBrian Somers     } else
401e2ebb036SBrian Somers       datalink_AuthOk(dl);
402e2ebb036SBrian Somers   }
403e2ebb036SBrian Somers }
404e2ebb036SBrian Somers 
405e2ebb036SBrian Somers void
406e2ebb036SBrian Somers datalink_AuthOk(struct datalink *dl)
407e2ebb036SBrian Somers {
4086d666775SBrian Somers   FsmUp(&dl->ccp.fsm);
4096d666775SBrian Somers   FsmOpen(&dl->ccp.fsm);
410e2ebb036SBrian Somers   dl->state = DATALINK_OPEN;
411a611cad6SBrian Somers   (*dl->parent->LayerUp)(dl->parent->object, &dl->lcp.fsm);
4126d666775SBrian Somers }
413e2ebb036SBrian Somers 
414e2ebb036SBrian Somers void
415e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl)
416e2ebb036SBrian Somers {
417e2ebb036SBrian Somers   dl->state = DATALINK_LCP;
418a611cad6SBrian Somers   FsmClose(&dl->lcp.fsm);
4196d666775SBrian Somers }
4206d666775SBrian Somers 
4216d666775SBrian Somers static void
4226d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp)
4236d666775SBrian Somers {
4246d666775SBrian Somers   /* The given FSM has been told to come down */
4256d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
426a611cad6SBrian Somers 
427a611cad6SBrian Somers   if (fp == &dl->lcp.fsm) {
428e2ebb036SBrian Somers     switch (dl->state) {
429e2ebb036SBrian Somers       case DATALINK_OPEN:
430e2ebb036SBrian Somers         FsmDown(&dl->ccp.fsm);
431e2ebb036SBrian Somers         FsmClose(&dl->ccp.fsm);
432e2ebb036SBrian Somers         (*dl->parent->LayerDown)(dl->parent->object, fp);
433e2ebb036SBrian Somers         /* fall through */
434e2ebb036SBrian Somers 
435e2ebb036SBrian Somers       case DATALINK_AUTH:
436e2ebb036SBrian Somers         StopTimer(&dl->pap.authtimer);
437e2ebb036SBrian Somers         StopTimer(&dl->chap.auth.authtimer);
4386d666775SBrian Somers     }
439e2ebb036SBrian Somers     dl->state = DATALINK_LCP;
440e2ebb036SBrian Somers   }
4416d666775SBrian Somers }
4426d666775SBrian Somers 
4436d666775SBrian Somers static void
4446d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp)
4456d666775SBrian Somers {
4466d666775SBrian Somers   /* The given fsm is now down */
4476d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
4486d666775SBrian Somers 
449a611cad6SBrian Somers   if (fp == &dl->lcp.fsm) {
4506d666775SBrian Somers     (*dl->parent->LayerFinish)(dl->parent->object, fp);
451e2ebb036SBrian Somers     datalink_ComeDown(dl, 0);
4526d666775SBrian Somers   }
4536d666775SBrian Somers }
4546d666775SBrian Somers 
4553006ec67SBrian Somers struct datalink *
4566d666775SBrian Somers datalink_Create(const char *name, struct bundle *bundle,
4576d666775SBrian Somers                 const struct fsm_parent *parent)
4583006ec67SBrian Somers {
4593006ec67SBrian Somers   struct datalink *dl;
4603006ec67SBrian Somers 
4613006ec67SBrian Somers   dl = (struct datalink *)malloc(sizeof(struct datalink));
4623006ec67SBrian Somers   if (dl == NULL)
4633006ec67SBrian Somers     return dl;
4643006ec67SBrian Somers 
4653006ec67SBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
4663006ec67SBrian Somers   dl->desc.next = NULL;
4673006ec67SBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
4683006ec67SBrian Somers   dl->desc.IsSet = datalink_IsSet;
4693006ec67SBrian Somers   dl->desc.Read = datalink_Read;
4703006ec67SBrian Somers   dl->desc.Write = datalink_Write;
4715b8b8060SBrian Somers 
472e718d1d7SBrian Somers   dl->state = DATALINK_CLOSED;
473e718d1d7SBrian Somers 
47473a13b5cSBrian Somers   *dl->cfg.script.dial = '\0';
47573a13b5cSBrian Somers   *dl->cfg.script.login = '\0';
47673a13b5cSBrian Somers   *dl->cfg.script.hangup = '\0';
477f9545805SBrian Somers   *dl->cfg.phone.list = '\0';
478f9545805SBrian Somers   *dl->phone.list = '\0';
479f9545805SBrian Somers   dl->phone.next = NULL;
480f9545805SBrian Somers   dl->phone.alt = NULL;
481f9545805SBrian Somers   dl->phone.chosen = "N/A";
482c7cc5030SBrian Somers   dl->script.run = 1;
483c7cc5030SBrian Somers   dl->script.packetmode = 1;
4845b8b8060SBrian Somers 
4853006ec67SBrian Somers   dl->bundle = bundle;
4863006ec67SBrian Somers   dl->next = NULL;
487e718d1d7SBrian Somers 
4883006ec67SBrian Somers   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
489e718d1d7SBrian Somers 
4903006ec67SBrian Somers   dl->dial_tries = 0;
49173a13b5cSBrian Somers   dl->cfg.max_dial = 1;
49273a13b5cSBrian Somers   dl->cfg.dial_timeout = DIAL_TIMEOUT;
49373a13b5cSBrian Somers   dl->cfg.dial_next_timeout = DIAL_NEXT_TIMEOUT;
494e718d1d7SBrian Somers 
495abff9baeSBrian Somers   dl->reconnect_tries = 0;
49673a13b5cSBrian Somers   dl->cfg.max_reconnect = 0;
49773a13b5cSBrian Somers   dl->cfg.reconnect_timeout = RECONNECT_TIMEOUT;
498abff9baeSBrian Somers 
4993006ec67SBrian Somers   dl->name = strdup(name);
500dc0fdb6bSBrian Somers   if ((dl->physical = modem_Create(dl->name, dl)) == NULL) {
5013006ec67SBrian Somers     free(dl->name);
5023006ec67SBrian Somers     free(dl);
5033006ec67SBrian Somers     return NULL;
5043006ec67SBrian Somers   }
505f9545805SBrian Somers   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
5063006ec67SBrian Somers 
5076d666775SBrian Somers   dl->parent = parent;
5086d666775SBrian Somers   dl->fsm.LayerStart = datalink_LayerStart;
5096d666775SBrian Somers   dl->fsm.LayerUp = datalink_LayerUp;
5106d666775SBrian Somers   dl->fsm.LayerDown = datalink_LayerDown;
5116d666775SBrian Somers   dl->fsm.LayerFinish = datalink_LayerFinish;
5126d666775SBrian Somers   dl->fsm.object = dl;
5136d666775SBrian Somers 
514a611cad6SBrian Somers   lcp_Init(&dl->lcp, dl->bundle, dl->physical, &dl->fsm);
5156d666775SBrian Somers   ccp_Init(&dl->ccp, dl->bundle, &dl->physical->link, &dl->fsm);
5163006ec67SBrian Somers 
517e2ebb036SBrian Somers   authinfo_Init(&dl->pap);
518e2ebb036SBrian Somers   authinfo_Init(&dl->chap.auth);
519e2ebb036SBrian Somers 
520c7cc5030SBrian Somers   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
5213006ec67SBrian Somers 
5223006ec67SBrian Somers   return dl;
5233006ec67SBrian Somers }
5243006ec67SBrian Somers 
5253006ec67SBrian Somers struct datalink *
5263006ec67SBrian Somers datalink_Destroy(struct datalink *dl)
5273006ec67SBrian Somers {
5283006ec67SBrian Somers   struct datalink *result;
5293006ec67SBrian Somers 
5303006ec67SBrian Somers   if (dl->state != DATALINK_CLOSED)
531c7cc5030SBrian Somers     LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n",
532c7cc5030SBrian Somers               datalink_State(dl));
5333006ec67SBrian Somers 
5343006ec67SBrian Somers   result = dl->next;
5353006ec67SBrian Somers   chat_Destroy(&dl->chat);
5363006ec67SBrian Somers   link_Destroy(&dl->physical->link);
5373006ec67SBrian Somers   free(dl->name);
5383006ec67SBrian Somers   free(dl);
5393006ec67SBrian Somers 
5403006ec67SBrian Somers   return result;
5413006ec67SBrian Somers }
5423006ec67SBrian Somers 
5433006ec67SBrian Somers void
544c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode)
5453006ec67SBrian Somers {
546c7cc5030SBrian Somers   switch (dl->state) {
547c7cc5030SBrian Somers     case DATALINK_CLOSED:
5483006ec67SBrian Somers       LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name);
5493006ec67SBrian Somers       dl->state = DATALINK_OPENING;
55073a13b5cSBrian Somers       dl->reconnect_tries = dl->cfg.max_reconnect;
55173a13b5cSBrian Somers       dl->dial_tries = dl->cfg.max_dial;
552c5a5a6caSBrian Somers       dl->script.run = runscripts;
553c5a5a6caSBrian Somers       dl->script.packetmode = packetmode;
554c7cc5030SBrian Somers       break;
555c7cc5030SBrian Somers 
556c7cc5030SBrian Somers     case DATALINK_OPENING:
557c7cc5030SBrian Somers       if (!dl->script.run && runscripts)
558c7cc5030SBrian Somers         dl->script.run = 1;
559c7cc5030SBrian Somers       /* fall through */
560c7cc5030SBrian Somers 
561c7cc5030SBrian Somers     case DATALINK_DIAL:
562c7cc5030SBrian Somers     case DATALINK_LOGIN:
563c7cc5030SBrian Somers     case DATALINK_READY:
564c7cc5030SBrian Somers       if (!dl->script.packetmode && packetmode) {
565c7cc5030SBrian Somers         dl->script.packetmode = 1;
566c7cc5030SBrian Somers         if (dl->state == DATALINK_READY)
567c7cc5030SBrian Somers           datalink_LoginDone(dl);
568c7cc5030SBrian Somers       }
569c7cc5030SBrian Somers       break;
5703006ec67SBrian Somers   }
5713006ec67SBrian Somers }
5723006ec67SBrian Somers 
5733006ec67SBrian Somers void
574c7cc5030SBrian Somers datalink_Close(struct datalink *dl, int stay)
575c7cc5030SBrian Somers {
576c7cc5030SBrian Somers   /* Please close */
577e2ebb036SBrian Somers   switch (dl->state) {
578e2ebb036SBrian Somers     case DATALINK_OPEN:
579e2ebb036SBrian Somers       FsmDown(&dl->ccp.fsm);
580f4768038SBrian Somers       FsmClose(&dl->ccp.fsm);
581e2ebb036SBrian Somers       /* fall through */
582e2ebb036SBrian Somers 
583e2ebb036SBrian Somers     case DATALINK_AUTH:
584e2ebb036SBrian Somers     case DATALINK_LCP:
585a611cad6SBrian Somers       FsmClose(&dl->lcp.fsm);
586c7cc5030SBrian Somers       if (stay) {
587c7cc5030SBrian Somers         dl->dial_tries = -1;
588c7cc5030SBrian Somers         dl->reconnect_tries = 0;
589c7cc5030SBrian Somers       }
590e2ebb036SBrian Somers       break;
591e2ebb036SBrian Somers 
592e2ebb036SBrian Somers     default:
593c7cc5030SBrian Somers       datalink_ComeDown(dl, stay);
594c7cc5030SBrian Somers   }
595e2ebb036SBrian Somers }
596c7cc5030SBrian Somers 
597c7cc5030SBrian Somers void
598c7cc5030SBrian Somers datalink_Down(struct datalink *dl, int stay)
599c7cc5030SBrian Somers {
600c7cc5030SBrian Somers   /* Carrier is lost */
601e2ebb036SBrian Somers   switch (dl->state) {
602e2ebb036SBrian Somers     case DATALINK_OPEN:
603f4768038SBrian Somers       FsmDown(&dl->ccp.fsm);
604f4768038SBrian Somers       FsmClose(&dl->ccp.fsm);
605e2ebb036SBrian Somers       /* fall through */
606e2ebb036SBrian Somers 
607e2ebb036SBrian Somers     case DATALINK_AUTH:
608e2ebb036SBrian Somers     case DATALINK_LCP:
609a611cad6SBrian Somers       FsmDown(&dl->lcp.fsm);
610c7cc5030SBrian Somers       if (stay)
611a611cad6SBrian Somers         FsmClose(&dl->lcp.fsm);
612c7cc5030SBrian Somers       else
613f4768038SBrian Somers         FsmOpen(&dl->ccp.fsm);
614e2ebb036SBrian Somers       /* fall through */
615c7cc5030SBrian Somers 
616e2ebb036SBrian Somers     default:
617c7cc5030SBrian Somers       datalink_ComeDown(dl, stay);
618c7cc5030SBrian Somers   }
619e2ebb036SBrian Somers }
620c7cc5030SBrian Somers 
621c7cc5030SBrian Somers void
6223006ec67SBrian Somers datalink_StayDown(struct datalink *dl)
6233006ec67SBrian Somers {
6243006ec67SBrian Somers   dl->reconnect_tries = 0;
6253006ec67SBrian Somers }
626c7cc5030SBrian Somers 
627c7cc5030SBrian Somers void
628c7cc5030SBrian Somers datalink_Show(struct datalink *dl)
629c7cc5030SBrian Somers {
630c7cc5030SBrian Somers   prompt_Printf(&prompt, "Link %s: State %s\n", dl->name, datalink_State(dl));
631c7cc5030SBrian Somers }
632c7cc5030SBrian Somers 
633c7cc5030SBrian Somers static char *states[] = {
634c7cc5030SBrian Somers   "CLOSED",
635c7cc5030SBrian Somers   "OPENING",
636c7cc5030SBrian Somers   "HANGUP",
637c7cc5030SBrian Somers   "DIAL",
638c7cc5030SBrian Somers   "LOGIN",
639c7cc5030SBrian Somers   "READY",
640e2ebb036SBrian Somers   "LCP"
641e2ebb036SBrian Somers   "AUTH"
642c7cc5030SBrian Somers   "OPEN"
643c7cc5030SBrian Somers };
644c7cc5030SBrian Somers 
645c7cc5030SBrian Somers static const char *
646c7cc5030SBrian Somers datalink_State(struct datalink *dl)
647c7cc5030SBrian Somers {
648c7cc5030SBrian Somers   if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
649c7cc5030SBrian Somers     return "unknown";
650c7cc5030SBrian Somers   return states[dl->state];
651c7cc5030SBrian Somers }
652