xref: /freebsd/usr.sbin/ppp/datalink.c (revision 3b0f8d2e)
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  *
263b0f8d2eSBrian Somers  *	$Id: datalink.c,v 1.1.2.28 1998/03/25 00:59:33 brian Exp $
273006ec67SBrian Somers  */
283006ec67SBrian Somers 
293006ec67SBrian Somers #include <sys/param.h>
303006ec67SBrian Somers #include <netinet/in.h>
31eaa4df37SBrian Somers #include <netinet/in_systm.h>
32eaa4df37SBrian Somers #include <netinet/ip.h>
333006ec67SBrian Somers 
343006ec67SBrian Somers #include <alias.h>
35c7cc5030SBrian Somers #include <stdio.h>
363006ec67SBrian Somers #include <stdlib.h>
373006ec67SBrian Somers #include <string.h>
383006ec67SBrian Somers #include <termios.h>
393006ec67SBrian Somers 
403006ec67SBrian Somers #include "command.h"
413006ec67SBrian Somers #include "mbuf.h"
423006ec67SBrian Somers #include "log.h"
433006ec67SBrian Somers #include "defs.h"
443006ec67SBrian Somers #include "loadalias.h"
453006ec67SBrian Somers #include "vars.h"
463006ec67SBrian Somers #include "timer.h"
473006ec67SBrian Somers #include "fsm.h"
483006ec67SBrian Somers #include "lcp.h"
493006ec67SBrian Somers #include "descriptor.h"
50879ed6faSBrian Somers #include "lqr.h"
513006ec67SBrian Somers #include "hdlc.h"
523006ec67SBrian Somers #include "async.h"
533006ec67SBrian Somers #include "throughput.h"
543b0f8d2eSBrian Somers #include "ccp.h"
553006ec67SBrian Somers #include "link.h"
563006ec67SBrian Somers #include "physical.h"
575828db6dSBrian Somers #include "iplist.h"
58eaa4df37SBrian Somers #include "slcompress.h"
595828db6dSBrian Somers #include "ipcp.h"
605ca5389aSBrian Somers #include "filter.h"
613b0f8d2eSBrian Somers #include "mp.h"
623006ec67SBrian Somers #include "bundle.h"
633006ec67SBrian Somers #include "chat.h"
64e2ebb036SBrian Somers #include "auth.h"
653006ec67SBrian Somers #include "main.h"
663006ec67SBrian Somers #include "modem.h"
67c7cc5030SBrian Somers #include "prompt.h"
68e2ebb036SBrian Somers #include "lcpproto.h"
69e2ebb036SBrian Somers #include "pap.h"
70e2ebb036SBrian Somers #include "chap.h"
71e2ebb036SBrian Somers #include "datalink.h"
72c7cc5030SBrian Somers 
73c7cc5030SBrian Somers static const char *datalink_State(struct datalink *);
743006ec67SBrian Somers 
753006ec67SBrian Somers static void
763006ec67SBrian Somers datalink_OpenTimeout(void *v)
773006ec67SBrian Somers {
783006ec67SBrian Somers   struct datalink *dl = (struct datalink *)v;
793006ec67SBrian Somers 
803006ec67SBrian Somers   StopTimer(&dl->dial_timer);
813006ec67SBrian Somers   if (dl->state == DATALINK_OPENING)
823006ec67SBrian Somers     LogPrintf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
833006ec67SBrian Somers }
843006ec67SBrian Somers 
853006ec67SBrian Somers static void
863006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout)
873006ec67SBrian Somers {
883006ec67SBrian Somers   StopTimer(&dl->dial_timer);
893006ec67SBrian Somers 
903006ec67SBrian Somers   if (Timeout) {
913006ec67SBrian Somers     dl->dial_timer.state = TIMER_STOPPED;
923006ec67SBrian Somers     if (Timeout > 0)
933006ec67SBrian Somers       dl->dial_timer.load = Timeout * SECTICKS;
943006ec67SBrian Somers     else
95e718d1d7SBrian Somers       dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
963006ec67SBrian Somers     dl->dial_timer.func = datalink_OpenTimeout;
973b0f8d2eSBrian Somers     dl->dial_timer.name = "dial";
983006ec67SBrian Somers     dl->dial_timer.arg = dl;
993006ec67SBrian Somers     StartTimer(&dl->dial_timer);
1003006ec67SBrian Somers     if (dl->state == DATALINK_OPENING)
1013006ec67SBrian Somers       LogPrintf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
1023006ec67SBrian Somers                 dl->name, Timeout);
1033006ec67SBrian Somers   }
1043006ec67SBrian Somers }
1053006ec67SBrian Somers 
1063006ec67SBrian Somers static void
1073006ec67SBrian Somers datalink_HangupDone(struct datalink *dl)
1083006ec67SBrian Somers {
1093006ec67SBrian Somers   modem_Close(dl->physical);
110f9545805SBrian Somers   dl->phone.chosen = "[N/A]";
1113006ec67SBrian Somers 
1123b0f8d2eSBrian Somers   if (dl->bundle->CleaningUp ||
1133b0f8d2eSBrian Somers       (mode & MODE_DIRECT) ||
1143b0f8d2eSBrian Somers       ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) &&
1153b0f8d2eSBrian Somers        !(mode & (MODE_DDIAL|MODE_DEDICATED)))) {
1163006ec67SBrian Somers     LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
1173006ec67SBrian Somers     dl->state = DATALINK_CLOSED;
1183006ec67SBrian Somers     dl->dial_tries = -1;
1193006ec67SBrian Somers     dl->reconnect_tries = 0;
1203006ec67SBrian Somers     bundle_LinkClosed(dl->bundle, dl);
1213b0f8d2eSBrian Somers     if (!dl->bundle->CleaningUp)
12273a13b5cSBrian Somers       datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
1233006ec67SBrian Somers   } else {
124aef795ccSBrian Somers     LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name);
1253006ec67SBrian Somers     dl->state = DATALINK_OPENING;
126abff9baeSBrian Somers     if (dl->dial_tries < 0) {
12773a13b5cSBrian Somers       datalink_StartDialTimer(dl, dl->cfg.reconnect_timeout);
12873a13b5cSBrian Somers       dl->dial_tries = dl->cfg.max_dial;
129abff9baeSBrian Somers       dl->reconnect_tries--;
130abff9baeSBrian Somers     } else {
131f9545805SBrian Somers       if (dl->phone.next == NULL)
13273a13b5cSBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
1333006ec67SBrian Somers       else
13473a13b5cSBrian Somers         datalink_StartDialTimer(dl, dl->cfg.dial_next_timeout);
1353006ec67SBrian Somers     }
136abff9baeSBrian Somers   }
137abff9baeSBrian Somers }
1383006ec67SBrian Somers 
139f9545805SBrian Somers static const char *
140f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl)
141f9545805SBrian Somers {
142f9545805SBrian Somers   char *phone;
143f9545805SBrian Somers 
144f9545805SBrian Somers   if (dl->phone.alt == NULL) {
145f9545805SBrian Somers     if (dl->phone.next == NULL) {
146f9545805SBrian Somers       strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
147f9545805SBrian Somers       dl->phone.list[sizeof dl->phone.list - 1] = '\0';
148f9545805SBrian Somers       dl->phone.next = dl->phone.list;
149f9545805SBrian Somers     }
150f9545805SBrian Somers     dl->phone.alt = strsep(&dl->phone.next, ":");
151f9545805SBrian Somers   }
152f9545805SBrian Somers   phone = strsep(&dl->phone.alt, "|");
153f9545805SBrian Somers   dl->phone.chosen = *phone ? phone : "[NONE]";
154f9545805SBrian Somers   if (*phone)
155f9545805SBrian Somers     LogPrintf(LogPHASE, "Phone: %s\n", phone);
156f9545805SBrian Somers   return phone;
157f9545805SBrian Somers }
158f9545805SBrian Somers 
159c5a5a6caSBrian Somers static void
160c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl)
161c5a5a6caSBrian Somers {
162d345321bSBrian Somers   if (!dl->script.packetmode) {
163d345321bSBrian Somers     dl->dial_tries = -1;
164d345321bSBrian Somers     LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name);
165d345321bSBrian Somers     dl->state = DATALINK_READY;
166d345321bSBrian Somers   } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
167c5a5a6caSBrian Somers     dl->dial_tries = 0;
168c5a5a6caSBrian Somers     LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n");
169c5a5a6caSBrian Somers     if (dl->script.run) {
170c5a5a6caSBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
171c5a5a6caSBrian Somers       dl->state = DATALINK_HANGUP;
172c5a5a6caSBrian Somers       modem_Offline(dl->physical);
173f9545805SBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
174c5a5a6caSBrian Somers     } else
175c5a5a6caSBrian Somers       datalink_HangupDone(dl);
176c5a5a6caSBrian Somers   } else {
177c7cc5030SBrian Somers     dl->dial_tries = -1;
178c7cc5030SBrian Somers 
1793b0f8d2eSBrian Somers     hdlc_Init(&dl->physical->hdlc);
1803b0f8d2eSBrian Somers     async_Init(&dl->physical->async);
1813b0f8d2eSBrian Somers 
1823b0f8d2eSBrian Somers     lcp_Setup(&dl->physical->link.lcp,
1833b0f8d2eSBrian Somers               dl->state == DATALINK_READY ? 0 : VarOpenMode);
1843b0f8d2eSBrian Somers     ccp_Setup(&dl->physical->link.ccp);
185503a7782SBrian Somers 
186e2ebb036SBrian Somers     LogPrintf(LogPHASE, "%s: Entering LCP state\n", dl->name);
187e2ebb036SBrian Somers     dl->state = DATALINK_LCP;
1883b0f8d2eSBrian Somers     FsmUp(&dl->physical->link.lcp.fsm);
1893b0f8d2eSBrian Somers     FsmOpen(&dl->physical->link.lcp.fsm);
190c5a5a6caSBrian Somers   }
191c5a5a6caSBrian Somers }
192c5a5a6caSBrian Somers 
1933006ec67SBrian Somers static int
1943006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
1953006ec67SBrian Somers                    int *n)
1963006ec67SBrian Somers {
1973006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
1983006ec67SBrian Somers   int result;
1993006ec67SBrian Somers 
200310c3babSBrian Somers   result = 0;
2013006ec67SBrian Somers   switch (dl->state) {
2023006ec67SBrian Somers     case DATALINK_CLOSED:
203310c3babSBrian Somers       break;
2043006ec67SBrian Somers 
2053006ec67SBrian Somers     case DATALINK_OPENING:
2063006ec67SBrian Somers       if (dl->dial_timer.state != TIMER_RUNNING) {
2073006ec67SBrian Somers         if (--dl->dial_tries < 0)
2083006ec67SBrian Somers           dl->dial_tries = 0;
2093006ec67SBrian Somers         if (modem_Open(dl->physical, dl->bundle) >= 0) {
210c5a5a6caSBrian Somers           if (dl->script.run) {
2113006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name);
2123006ec67SBrian Somers             dl->state = DATALINK_DIAL;
213f9545805SBrian Somers             chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
214f9545805SBrian Somers                       datalink_ChoosePhoneNumber(dl));
21573a13b5cSBrian Somers             if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
2163006ec67SBrian Somers               LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n",
21773a13b5cSBrian Somers                         dl->name, dl->cfg.max_dial - dl->dial_tries,
21873a13b5cSBrian Somers                         dl->cfg.max_dial);
219c5a5a6caSBrian Somers           } else
220c5a5a6caSBrian Somers             datalink_LoginDone(dl);
2213006ec67SBrian Somers         } else {
22273a13b5cSBrian Somers           if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
2233006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
22473a13b5cSBrian Somers                       dl->cfg.max_dial - dl->dial_tries, dl->cfg.max_dial);
2253006ec67SBrian Somers           else
2263006ec67SBrian Somers             LogPrintf(LogCHAT, "Failed to open modem\n");
2273006ec67SBrian Somers 
2283b0f8d2eSBrian Somers           if (dl->bundle->CleaningUp ||
2293b0f8d2eSBrian Somers               (!(mode & (MODE_DDIAL|MODE_DEDICATED)) &&
2303b0f8d2eSBrian Somers                dl->cfg.max_dial && dl->dial_tries == 0)) {
2313006ec67SBrian Somers             LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
2323006ec67SBrian Somers             dl->state = DATALINK_CLOSED;
2333006ec67SBrian Somers             dl->reconnect_tries = 0;
2343006ec67SBrian Somers             dl->dial_tries = -1;
2355b8b8060SBrian Somers             bundle_LinkClosed(dl->bundle, dl);
236c5a5a6caSBrian Somers           }
2373b0f8d2eSBrian Somers           if (!dl->bundle->CleaningUp)
23873a13b5cSBrian Somers             datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
2393006ec67SBrian Somers         }
2403006ec67SBrian Somers       }
241310c3babSBrian Somers       break;
2423006ec67SBrian Somers 
2433006ec67SBrian Somers     case DATALINK_HANGUP:
2443006ec67SBrian Somers     case DATALINK_DIAL:
2453006ec67SBrian Somers     case DATALINK_LOGIN:
2463006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
2473006ec67SBrian Somers       switch (dl->chat.state) {
2483006ec67SBrian Somers         case CHAT_DONE:
2493006ec67SBrian Somers           /* script succeeded */
2503006ec67SBrian Somers           switch(dl->state) {
2513006ec67SBrian Somers             case DATALINK_HANGUP:
2523006ec67SBrian Somers               datalink_HangupDone(dl);
2533006ec67SBrian Somers               break;
2543006ec67SBrian Somers             case DATALINK_DIAL:
2553006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name);
2563006ec67SBrian Somers               dl->state = DATALINK_LOGIN;
257f9545805SBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
2583006ec67SBrian Somers               break;
2593006ec67SBrian Somers             case DATALINK_LOGIN:
260c5a5a6caSBrian Somers               datalink_LoginDone(dl);
2613006ec67SBrian Somers               break;
2623006ec67SBrian Somers           }
2633006ec67SBrian Somers           break;
2643006ec67SBrian Somers         case CHAT_FAILED:
2653006ec67SBrian Somers           /* Going down - script failed */
2663006ec67SBrian Somers           LogPrintf(LogWARN, "Chat script failed\n");
2673006ec67SBrian Somers           switch(dl->state) {
2683006ec67SBrian Somers             case DATALINK_HANGUP:
2693006ec67SBrian Somers               datalink_HangupDone(dl);
2703006ec67SBrian Somers               break;
2713006ec67SBrian Somers             case DATALINK_DIAL:
2723006ec67SBrian Somers             case DATALINK_LOGIN:
2733006ec67SBrian Somers               LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
2743006ec67SBrian Somers               dl->state = DATALINK_HANGUP;
2753006ec67SBrian Somers               modem_Offline(dl->physical);
276f9545805SBrian Somers               chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
2773006ec67SBrian Somers               break;
2783006ec67SBrian Somers           }
2793006ec67SBrian Somers           break;
2803006ec67SBrian Somers       }
2813006ec67SBrian Somers       break;
282c7cc5030SBrian Somers 
283c7cc5030SBrian Somers     case DATALINK_READY:
284e2ebb036SBrian Somers     case DATALINK_LCP:
285e2ebb036SBrian Somers     case DATALINK_AUTH:
2863006ec67SBrian Somers     case DATALINK_OPEN:
2873006ec67SBrian Somers       result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
2883006ec67SBrian Somers       break;
2893006ec67SBrian Somers   }
2903006ec67SBrian Somers   return result;
2913006ec67SBrian Somers }
2923006ec67SBrian Somers 
2933006ec67SBrian Somers static int
2942f786681SBrian Somers datalink_IsSet(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       return descriptor_IsSet(&dl->chat.desc, fdset);
307c7cc5030SBrian Somers 
308c7cc5030SBrian Somers     case DATALINK_READY:
309e2ebb036SBrian Somers     case DATALINK_LCP:
310e2ebb036SBrian Somers     case DATALINK_AUTH:
3113006ec67SBrian Somers     case DATALINK_OPEN:
3123006ec67SBrian Somers       return descriptor_IsSet(&dl->physical->desc, fdset);
3133006ec67SBrian Somers   }
3143006ec67SBrian Somers   return 0;
3153006ec67SBrian Somers }
3163006ec67SBrian Somers 
3173006ec67SBrian Somers static void
3183006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
3193006ec67SBrian Somers {
3203006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
3213006ec67SBrian Somers 
3223006ec67SBrian Somers   switch (dl->state) {
3233006ec67SBrian Somers     case DATALINK_CLOSED:
324c7cc5030SBrian Somers     case DATALINK_OPENING:
3253006ec67SBrian Somers       break;
326c7cc5030SBrian Somers 
3273006ec67SBrian Somers     case DATALINK_HANGUP:
3283006ec67SBrian Somers     case DATALINK_DIAL:
3293006ec67SBrian Somers     case DATALINK_LOGIN:
3303006ec67SBrian Somers       descriptor_Read(&dl->chat.desc, bundle, fdset);
3313006ec67SBrian Somers       break;
332c7cc5030SBrian Somers 
333c7cc5030SBrian Somers     case DATALINK_READY:
334e2ebb036SBrian Somers     case DATALINK_LCP:
335e2ebb036SBrian Somers     case DATALINK_AUTH:
3363006ec67SBrian Somers     case DATALINK_OPEN:
3373006ec67SBrian Somers       descriptor_Read(&dl->physical->desc, bundle, fdset);
3383006ec67SBrian Somers       break;
3393006ec67SBrian Somers   }
3403006ec67SBrian Somers }
3413006ec67SBrian Somers 
3423006ec67SBrian Somers static void
343f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
3443006ec67SBrian Somers {
3453006ec67SBrian Somers   struct datalink *dl = descriptor2datalink(d);
3463006ec67SBrian Somers 
3473006ec67SBrian Somers   switch (dl->state) {
3483006ec67SBrian Somers     case DATALINK_CLOSED:
349c7cc5030SBrian Somers     case DATALINK_OPENING:
3503006ec67SBrian Somers       break;
351c7cc5030SBrian Somers 
3523006ec67SBrian Somers     case DATALINK_HANGUP:
3533006ec67SBrian Somers     case DATALINK_DIAL:
3543006ec67SBrian Somers     case DATALINK_LOGIN:
355f4768038SBrian Somers       descriptor_Write(&dl->chat.desc, bundle, fdset);
3563006ec67SBrian Somers       break;
357c7cc5030SBrian Somers 
358c7cc5030SBrian Somers     case DATALINK_READY:
359e2ebb036SBrian Somers     case DATALINK_LCP:
360e2ebb036SBrian Somers     case DATALINK_AUTH:
3613006ec67SBrian Somers     case DATALINK_OPEN:
362f4768038SBrian Somers       descriptor_Write(&dl->physical->desc, bundle, fdset);
3633006ec67SBrian Somers       break;
3643006ec67SBrian Somers   }
3653006ec67SBrian Somers }
3663006ec67SBrian Somers 
3676d666775SBrian Somers static void
368e2ebb036SBrian Somers datalink_ComeDown(struct datalink *dl, int stay)
369e2ebb036SBrian Somers {
370e2ebb036SBrian Somers   if (stay) {
371e2ebb036SBrian Somers     dl->dial_tries = -1;
372e2ebb036SBrian Somers     dl->reconnect_tries = 0;
373e2ebb036SBrian Somers   }
374e2ebb036SBrian Somers 
375e2ebb036SBrian Somers   if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
376e2ebb036SBrian Somers     modem_Offline(dl->physical);
377e2ebb036SBrian Somers     if (dl->script.run && dl->state != DATALINK_OPENING) {
378e2ebb036SBrian Somers       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
379e2ebb036SBrian Somers       dl->state = DATALINK_HANGUP;
380f9545805SBrian Somers       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
381e2ebb036SBrian Somers     } else
382e2ebb036SBrian Somers       datalink_HangupDone(dl);
383e2ebb036SBrian Somers   }
384e2ebb036SBrian Somers }
385e2ebb036SBrian Somers 
386e2ebb036SBrian Somers static void
3876d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp)
3886d666775SBrian Somers {
3896d666775SBrian Somers   /* The given FSM is about to start up ! */
3906d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
391a611cad6SBrian Somers 
39292e872e7SBrian Somers   if (fp->proto == PROTO_LCP)
393e2ebb036SBrian Somers     (*dl->parent->LayerStart)(dl->parent->object, fp);
394e2ebb036SBrian Somers }
3956d666775SBrian Somers 
3966d666775SBrian Somers static void
3976d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp)
3986d666775SBrian Somers {
3996d666775SBrian Somers   /* The given fsm is now up */
4006d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
4016d666775SBrian Somers 
40292e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
4033b0f8d2eSBrian Somers     dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
4043b0f8d2eSBrian Somers     dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
4053b0f8d2eSBrian Somers     if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
4063b0f8d2eSBrian Somers       if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
4075563ebdeSBrian Somers         bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
408e2ebb036SBrian Somers       LogPrintf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
4093b0f8d2eSBrian Somers                 Auth2Nam(dl->physical->link.lcp.his_auth),
4103b0f8d2eSBrian Somers                 Auth2Nam(dl->physical->link.lcp.want_auth));
4113b0f8d2eSBrian Somers       if (dl->physical->link.lcp.his_auth == PROTO_PAP)
412e2ebb036SBrian Somers         StartAuthChallenge(&dl->pap, dl->physical, SendPapChallenge);
4133b0f8d2eSBrian Somers       if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
414e2ebb036SBrian Somers         StartAuthChallenge(&dl->chap.auth, dl->physical, SendChapChallenge);
415e2ebb036SBrian Somers     } else
416e2ebb036SBrian Somers       datalink_AuthOk(dl);
417e2ebb036SBrian Somers   }
418e2ebb036SBrian Somers }
419e2ebb036SBrian Somers 
420e2ebb036SBrian Somers void
421e2ebb036SBrian Somers datalink_AuthOk(struct datalink *dl)
422e2ebb036SBrian Somers {
4233b0f8d2eSBrian Somers   /* XXX: Connect to another ppp instance HERE */
4243b0f8d2eSBrian Somers 
4253b0f8d2eSBrian Somers   FsmUp(&dl->physical->link.ccp.fsm);
4263b0f8d2eSBrian Somers   FsmOpen(&dl->physical->link.ccp.fsm);
427e2ebb036SBrian Somers   dl->state = DATALINK_OPEN;
4283b0f8d2eSBrian Somers   bundle_NewPhase(dl->bundle, PHASE_NETWORK);
4293b0f8d2eSBrian Somers   (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
4306d666775SBrian Somers }
431e2ebb036SBrian Somers 
432e2ebb036SBrian Somers void
433e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl)
434e2ebb036SBrian Somers {
435e2ebb036SBrian Somers   dl->state = DATALINK_LCP;
4363b0f8d2eSBrian Somers   FsmClose(&dl->physical->link.lcp.fsm);
4376d666775SBrian Somers }
4386d666775SBrian Somers 
4396d666775SBrian Somers static void
4406d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp)
4416d666775SBrian Somers {
4426d666775SBrian Somers   /* The given FSM has been told to come down */
4436d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
444a611cad6SBrian Somers 
44592e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
446e2ebb036SBrian Somers     switch (dl->state) {
447e2ebb036SBrian Somers       case DATALINK_OPEN:
4483b0f8d2eSBrian Somers         FsmDown(&dl->physical->link.ccp.fsm);
4493b0f8d2eSBrian Somers         FsmClose(&dl->physical->link.ccp.fsm);
450e2ebb036SBrian Somers         (*dl->parent->LayerDown)(dl->parent->object, fp);
451e2ebb036SBrian Somers         /* fall through */
452e2ebb036SBrian Somers 
453e2ebb036SBrian Somers       case DATALINK_AUTH:
454e2ebb036SBrian Somers         StopTimer(&dl->pap.authtimer);
455e2ebb036SBrian Somers         StopTimer(&dl->chap.auth.authtimer);
4566d666775SBrian Somers     }
457e2ebb036SBrian Somers     dl->state = DATALINK_LCP;
458e2ebb036SBrian Somers   }
4596d666775SBrian Somers }
4606d666775SBrian Somers 
4616d666775SBrian Somers static void
4626d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp)
4636d666775SBrian Somers {
4646d666775SBrian Somers   /* The given fsm is now down */
4656d666775SBrian Somers   struct datalink *dl = (struct datalink *)v;
4666d666775SBrian Somers 
46792e872e7SBrian Somers   if (fp->proto == PROTO_LCP) {
46892e872e7SBrian Somers     FsmDown(fp);	/* Bring us to INITIAL or STARTING */
4696d666775SBrian Somers     (*dl->parent->LayerFinish)(dl->parent->object, fp);
470e2ebb036SBrian Somers     datalink_ComeDown(dl, 0);
4716d666775SBrian Somers   }
4726d666775SBrian Somers }
4736d666775SBrian Somers 
4743006ec67SBrian Somers struct datalink *
4756d666775SBrian Somers datalink_Create(const char *name, struct bundle *bundle,
4766d666775SBrian Somers                 const struct fsm_parent *parent)
4773006ec67SBrian Somers {
4783006ec67SBrian Somers   struct datalink *dl;
4793006ec67SBrian Somers 
4803006ec67SBrian Somers   dl = (struct datalink *)malloc(sizeof(struct datalink));
4813006ec67SBrian Somers   if (dl == NULL)
4823006ec67SBrian Somers     return dl;
4833006ec67SBrian Somers 
4843006ec67SBrian Somers   dl->desc.type = DATALINK_DESCRIPTOR;
4853006ec67SBrian Somers   dl->desc.next = NULL;
4863006ec67SBrian Somers   dl->desc.UpdateSet = datalink_UpdateSet;
4873006ec67SBrian Somers   dl->desc.IsSet = datalink_IsSet;
4883006ec67SBrian Somers   dl->desc.Read = datalink_Read;
4893006ec67SBrian Somers   dl->desc.Write = datalink_Write;
4905b8b8060SBrian Somers 
491e718d1d7SBrian Somers   dl->state = DATALINK_CLOSED;
492e718d1d7SBrian Somers 
49373a13b5cSBrian Somers   *dl->cfg.script.dial = '\0';
49473a13b5cSBrian Somers   *dl->cfg.script.login = '\0';
49573a13b5cSBrian Somers   *dl->cfg.script.hangup = '\0';
496f9545805SBrian Somers   *dl->cfg.phone.list = '\0';
497f9545805SBrian Somers   *dl->phone.list = '\0';
498f9545805SBrian Somers   dl->phone.next = NULL;
499f9545805SBrian Somers   dl->phone.alt = NULL;
500f9545805SBrian Somers   dl->phone.chosen = "N/A";
501c7cc5030SBrian Somers   dl->script.run = 1;
502c7cc5030SBrian Somers   dl->script.packetmode = 1;
5033b0f8d2eSBrian Somers   mp_linkInit(&dl->mp);
5045b8b8060SBrian Somers 
5053006ec67SBrian Somers   dl->bundle = bundle;
5063006ec67SBrian Somers   dl->next = NULL;
507e718d1d7SBrian Somers 
5083006ec67SBrian Somers   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
509e718d1d7SBrian Somers 
5103006ec67SBrian Somers   dl->dial_tries = 0;
51173a13b5cSBrian Somers   dl->cfg.max_dial = 1;
51273a13b5cSBrian Somers   dl->cfg.dial_timeout = DIAL_TIMEOUT;
51373a13b5cSBrian Somers   dl->cfg.dial_next_timeout = DIAL_NEXT_TIMEOUT;
514e718d1d7SBrian Somers 
515abff9baeSBrian Somers   dl->reconnect_tries = 0;
51673a13b5cSBrian Somers   dl->cfg.max_reconnect = 0;
51773a13b5cSBrian Somers   dl->cfg.reconnect_timeout = RECONNECT_TIMEOUT;
518abff9baeSBrian Somers 
5193006ec67SBrian Somers   dl->name = strdup(name);
5203b0f8d2eSBrian Somers   dl->parent = parent;
5213b0f8d2eSBrian Somers   dl->fsmp.LayerStart = datalink_LayerStart;
5223b0f8d2eSBrian Somers   dl->fsmp.LayerUp = datalink_LayerUp;
5233b0f8d2eSBrian Somers   dl->fsmp.LayerDown = datalink_LayerDown;
5243b0f8d2eSBrian Somers   dl->fsmp.LayerFinish = datalink_LayerFinish;
5253b0f8d2eSBrian Somers   dl->fsmp.object = dl;
5263b0f8d2eSBrian Somers 
5273b0f8d2eSBrian Somers   authinfo_Init(&dl->pap);
5283b0f8d2eSBrian Somers   authinfo_Init(&dl->chap.auth);
5293b0f8d2eSBrian Somers 
5303b0f8d2eSBrian Somers   if ((dl->physical = modem_Create(dl)) == NULL) {
5313006ec67SBrian Somers     free(dl->name);
5323006ec67SBrian Somers     free(dl);
5333006ec67SBrian Somers     return NULL;
5343006ec67SBrian Somers   }
535f9545805SBrian Somers   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
5363006ec67SBrian Somers 
537c7cc5030SBrian Somers   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
5383006ec67SBrian Somers 
5393006ec67SBrian Somers   return dl;
5403006ec67SBrian Somers }
5413006ec67SBrian Somers 
5423006ec67SBrian Somers struct datalink *
5433006ec67SBrian Somers datalink_Destroy(struct datalink *dl)
5443006ec67SBrian Somers {
5453006ec67SBrian Somers   struct datalink *result;
5463006ec67SBrian Somers 
5473006ec67SBrian Somers   if (dl->state != DATALINK_CLOSED)
548c7cc5030SBrian Somers     LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n",
549c7cc5030SBrian Somers               datalink_State(dl));
5503006ec67SBrian Somers 
5513006ec67SBrian Somers   result = dl->next;
5523006ec67SBrian Somers   chat_Destroy(&dl->chat);
5533b0f8d2eSBrian Somers   modem_Destroy(dl->physical);
5543006ec67SBrian Somers   free(dl->name);
5553006ec67SBrian Somers   free(dl);
5563006ec67SBrian Somers 
5573006ec67SBrian Somers   return result;
5583006ec67SBrian Somers }
5593006ec67SBrian Somers 
5603006ec67SBrian Somers void
561c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode)
5623006ec67SBrian Somers {
563c7cc5030SBrian Somers   switch (dl->state) {
564c7cc5030SBrian Somers     case DATALINK_CLOSED:
5653006ec67SBrian Somers       LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name);
5663b0f8d2eSBrian Somers       if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
5673b0f8d2eSBrian Somers           bundle_Phase(dl->bundle) == PHASE_TERMINATE)
5683b0f8d2eSBrian Somers         bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
5693006ec67SBrian Somers       dl->state = DATALINK_OPENING;
57073a13b5cSBrian Somers       dl->reconnect_tries = dl->cfg.max_reconnect;
57173a13b5cSBrian Somers       dl->dial_tries = dl->cfg.max_dial;
572c5a5a6caSBrian Somers       dl->script.run = runscripts;
573c5a5a6caSBrian Somers       dl->script.packetmode = packetmode;
574c7cc5030SBrian Somers       break;
575c7cc5030SBrian Somers 
576c7cc5030SBrian Somers     case DATALINK_OPENING:
577c7cc5030SBrian Somers       if (!dl->script.run && runscripts)
578c7cc5030SBrian Somers         dl->script.run = 1;
579c7cc5030SBrian Somers       /* fall through */
580c7cc5030SBrian Somers 
581c7cc5030SBrian Somers     case DATALINK_DIAL:
582c7cc5030SBrian Somers     case DATALINK_LOGIN:
583c7cc5030SBrian Somers     case DATALINK_READY:
584c7cc5030SBrian Somers       if (!dl->script.packetmode && packetmode) {
585c7cc5030SBrian Somers         dl->script.packetmode = 1;
586c7cc5030SBrian Somers         if (dl->state == DATALINK_READY)
587c7cc5030SBrian Somers           datalink_LoginDone(dl);
588c7cc5030SBrian Somers       }
589c7cc5030SBrian Somers       break;
5903006ec67SBrian Somers   }
5913006ec67SBrian Somers }
5923006ec67SBrian Somers 
5933006ec67SBrian Somers void
594c7cc5030SBrian Somers datalink_Close(struct datalink *dl, int stay)
595c7cc5030SBrian Somers {
596c7cc5030SBrian Somers   /* Please close */
597e2ebb036SBrian Somers   switch (dl->state) {
598e2ebb036SBrian Somers     case DATALINK_OPEN:
5993b0f8d2eSBrian Somers       FsmDown(&dl->physical->link.ccp.fsm);
6003b0f8d2eSBrian Somers       FsmClose(&dl->physical->link.ccp.fsm);
601e2ebb036SBrian Somers       /* fall through */
602e2ebb036SBrian Somers 
603e2ebb036SBrian Somers     case DATALINK_AUTH:
604e2ebb036SBrian Somers     case DATALINK_LCP:
6053b0f8d2eSBrian Somers       FsmClose(&dl->physical->link.lcp.fsm);
606c7cc5030SBrian Somers       if (stay) {
607c7cc5030SBrian Somers         dl->dial_tries = -1;
608c7cc5030SBrian Somers         dl->reconnect_tries = 0;
609c7cc5030SBrian Somers       }
610e2ebb036SBrian Somers       break;
611e2ebb036SBrian Somers 
612e2ebb036SBrian Somers     default:
613c7cc5030SBrian Somers       datalink_ComeDown(dl, stay);
614c7cc5030SBrian Somers   }
615e2ebb036SBrian Somers }
616c7cc5030SBrian Somers 
617c7cc5030SBrian Somers void
618c7cc5030SBrian Somers datalink_Down(struct datalink *dl, int stay)
619c7cc5030SBrian Somers {
620c7cc5030SBrian Somers   /* Carrier is lost */
621e2ebb036SBrian Somers   switch (dl->state) {
622e2ebb036SBrian Somers     case DATALINK_OPEN:
6233b0f8d2eSBrian Somers       FsmDown(&dl->physical->link.ccp.fsm);
6243b0f8d2eSBrian Somers       FsmClose(&dl->physical->link.ccp.fsm);
625e2ebb036SBrian Somers       /* fall through */
626e2ebb036SBrian Somers 
627e2ebb036SBrian Somers     case DATALINK_AUTH:
628e2ebb036SBrian Somers     case DATALINK_LCP:
6293b0f8d2eSBrian Somers       FsmDown(&dl->physical->link.lcp.fsm);
630c7cc5030SBrian Somers       if (stay)
6313b0f8d2eSBrian Somers         FsmClose(&dl->physical->link.lcp.fsm);
632c7cc5030SBrian Somers       else
6333b0f8d2eSBrian Somers         FsmOpen(&dl->physical->link.ccp.fsm);
634e2ebb036SBrian Somers       /* fall through */
635c7cc5030SBrian Somers 
636e2ebb036SBrian Somers     default:
637c7cc5030SBrian Somers       datalink_ComeDown(dl, stay);
638c7cc5030SBrian Somers   }
639e2ebb036SBrian Somers }
640c7cc5030SBrian Somers 
641c7cc5030SBrian Somers void
6423006ec67SBrian Somers datalink_StayDown(struct datalink *dl)
6433006ec67SBrian Somers {
6443006ec67SBrian Somers   dl->reconnect_tries = 0;
6453006ec67SBrian Somers }
646c7cc5030SBrian Somers 
647c7cc5030SBrian Somers void
648c7cc5030SBrian Somers datalink_Show(struct datalink *dl)
649c7cc5030SBrian Somers {
650c7cc5030SBrian Somers   prompt_Printf(&prompt, "Link %s: State %s\n", dl->name, datalink_State(dl));
651c7cc5030SBrian Somers }
652c7cc5030SBrian Somers 
653c7cc5030SBrian Somers static char *states[] = {
654c7cc5030SBrian Somers   "CLOSED",
655c7cc5030SBrian Somers   "OPENING",
656c7cc5030SBrian Somers   "HANGUP",
657c7cc5030SBrian Somers   "DIAL",
658c7cc5030SBrian Somers   "LOGIN",
659c7cc5030SBrian Somers   "READY",
660e2ebb036SBrian Somers   "LCP"
661e2ebb036SBrian Somers   "AUTH"
662c7cc5030SBrian Somers   "OPEN"
663c7cc5030SBrian Somers };
664c7cc5030SBrian Somers 
665c7cc5030SBrian Somers static const char *
666c7cc5030SBrian Somers datalink_State(struct datalink *dl)
667c7cc5030SBrian Somers {
668c7cc5030SBrian Somers   if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
669c7cc5030SBrian Somers     return "unknown";
670c7cc5030SBrian Somers   return states[dl->state];
671c7cc5030SBrian Somers }
672