xref: /freebsd/usr.sbin/ppp/datalink.c (revision 565e35e50e2cdac423588a3d18742544bde128b0)
1 /*-
2  * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$Id: datalink.c,v 1.1.2.35 1998/04/07 00:53:35 brian Exp $
27  */
28 
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <termios.h>
38 
39 #include "mbuf.h"
40 #include "log.h"
41 #include "defs.h"
42 #include "timer.h"
43 #include "fsm.h"
44 #include "lcp.h"
45 #include "descriptor.h"
46 #include "lqr.h"
47 #include "hdlc.h"
48 #include "async.h"
49 #include "throughput.h"
50 #include "ccp.h"
51 #include "link.h"
52 #include "physical.h"
53 #include "iplist.h"
54 #include "slcompress.h"
55 #include "ipcp.h"
56 #include "filter.h"
57 #include "mp.h"
58 #include "bundle.h"
59 #include "chat.h"
60 #include "auth.h"
61 #include "modem.h"
62 #include "prompt.h"
63 #include "lcpproto.h"
64 #include "pap.h"
65 #include "chap.h"
66 #include "command.h"
67 #include "datalink.h"
68 
69 static const char *datalink_State(struct datalink *);
70 
71 static void
72 datalink_OpenTimeout(void *v)
73 {
74   struct datalink *dl = (struct datalink *)v;
75 
76   StopTimer(&dl->dial_timer);
77   if (dl->state == DATALINK_OPENING)
78     LogPrintf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
79 }
80 
81 static void
82 datalink_StartDialTimer(struct datalink *dl, int Timeout)
83 {
84   StopTimer(&dl->dial_timer);
85 
86   if (Timeout) {
87     dl->dial_timer.state = TIMER_STOPPED;
88     if (Timeout > 0)
89       dl->dial_timer.load = Timeout * SECTICKS;
90     else
91       dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
92     dl->dial_timer.func = datalink_OpenTimeout;
93     dl->dial_timer.name = "dial";
94     dl->dial_timer.arg = dl;
95     StartTimer(&dl->dial_timer);
96     if (dl->state == DATALINK_OPENING)
97       LogPrintf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
98                 dl->name, Timeout);
99   }
100 }
101 
102 static void
103 datalink_HangupDone(struct datalink *dl)
104 {
105   modem_Close(dl->physical);
106   dl->phone.chosen = "N/A";
107 
108   if (dl->bundle->CleaningUp ||
109       (dl->physical->type == PHYS_STDIN) ||
110       ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) &&
111        !(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)))) {
112     LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
113     dl->state = DATALINK_CLOSED;
114     dl->dial_tries = -1;
115     dl->reconnect_tries = 0;
116     bundle_LinkClosed(dl->bundle, dl);
117     if (!dl->bundle->CleaningUp)
118       datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
119   } else {
120     LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name);
121     dl->state = DATALINK_OPENING;
122     if (dl->dial_tries < 0) {
123       datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
124       dl->dial_tries = dl->cfg.dial.max;
125       dl->reconnect_tries--;
126     } else {
127       if (dl->phone.next == NULL)
128         datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
129       else
130         datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
131     }
132   }
133 }
134 
135 static const char *
136 datalink_ChoosePhoneNumber(struct datalink *dl)
137 {
138   char *phone;
139 
140   if (dl->phone.alt == NULL) {
141     if (dl->phone.next == NULL) {
142       strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
143       dl->phone.list[sizeof dl->phone.list - 1] = '\0';
144       dl->phone.next = dl->phone.list;
145     }
146     dl->phone.alt = strsep(&dl->phone.next, ":");
147   }
148   phone = strsep(&dl->phone.alt, "|");
149   dl->phone.chosen = *phone ? phone : "[NONE]";
150   if (*phone)
151     LogPrintf(LogPHASE, "Phone: %s\n", phone);
152   return phone;
153 }
154 
155 static void
156 datalink_LoginDone(struct datalink *dl)
157 {
158   if (!dl->script.packetmode) {
159     dl->dial_tries = -1;
160     LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name);
161     dl->state = DATALINK_READY;
162   } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
163     dl->dial_tries = 0;
164     LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n");
165     if (dl->script.run) {
166       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
167       dl->state = DATALINK_HANGUP;
168       modem_Offline(dl->physical);
169       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
170     } else
171       datalink_HangupDone(dl);
172   } else {
173     dl->dial_tries = -1;
174 
175     hdlc_Init(&dl->physical->hdlc);
176     async_Init(&dl->physical->async);
177 
178     lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
179               0 : dl->physical->link.lcp.cfg.openmode);
180     ccp_Setup(&dl->physical->link.ccp);
181 
182     LogPrintf(LogPHASE, "%s: Entering LCP state\n", dl->name);
183     dl->state = DATALINK_LCP;
184     FsmUp(&dl->physical->link.lcp.fsm);
185     FsmOpen(&dl->physical->link.lcp.fsm);
186   }
187 }
188 
189 static int
190 datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
191                    int *n)
192 {
193   struct datalink *dl = descriptor2datalink(d);
194   int result;
195 
196   result = 0;
197   switch (dl->state) {
198     case DATALINK_CLOSED:
199       if ((dl->physical->type & (PHYS_STDIN|PHYS_DEDICATED|PHYS_1OFF)) &&
200           !bundle_IsDead(dl->bundle))
201         /*
202          * Our first time in - DEDICATED never comes down, and STDIN & 1OFF
203          * get deleted when they enter DATALINK_CLOSED.  Go to
204          * DATALINK_OPENING via datalink_Up() and fall through.
205          */
206         datalink_Up(dl, 1, 1);
207       else
208         break;
209       /* fall through */
210 
211     case DATALINK_OPENING:
212       if (dl->dial_timer.state != TIMER_RUNNING) {
213         if (--dl->dial_tries < 0)
214           dl->dial_tries = 0;
215         if (modem_Open(dl->physical, dl->bundle) >= 0) {
216           if (dl->script.run) {
217             LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name);
218             dl->state = DATALINK_DIAL;
219             chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
220                       datalink_ChoosePhoneNumber(dl));
221             if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) &&
222                 dl->cfg.dial.max)
223               LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n",
224                         dl->name, dl->cfg.dial.max - dl->dial_tries,
225                         dl->cfg.dial.max);
226           } else
227             datalink_LoginDone(dl);
228         } else {
229           if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) &&
230               dl->cfg.dial.max)
231             LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
232                       dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max);
233           else
234             LogPrintf(LogCHAT, "Failed to open modem\n");
235 
236           if (dl->bundle->CleaningUp ||
237               (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) &&
238                dl->cfg.dial.max && dl->dial_tries == 0)) {
239             LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
240             dl->state = DATALINK_CLOSED;
241             dl->reconnect_tries = 0;
242             dl->dial_tries = -1;
243             bundle_LinkClosed(dl->bundle, dl);
244           }
245           if (!dl->bundle->CleaningUp)
246             datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
247         }
248       }
249       break;
250 
251     case DATALINK_HANGUP:
252     case DATALINK_DIAL:
253     case DATALINK_LOGIN:
254       result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
255       switch (dl->chat.state) {
256         case CHAT_DONE:
257           /* script succeeded */
258           switch(dl->state) {
259             case DATALINK_HANGUP:
260               datalink_HangupDone(dl);
261               break;
262             case DATALINK_DIAL:
263               LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name);
264               dl->state = DATALINK_LOGIN;
265               chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
266               break;
267             case DATALINK_LOGIN:
268               datalink_LoginDone(dl);
269               break;
270           }
271           break;
272         case CHAT_FAILED:
273           /* Going down - script failed */
274           LogPrintf(LogWARN, "Chat script failed\n");
275           switch(dl->state) {
276             case DATALINK_HANGUP:
277               datalink_HangupDone(dl);
278               break;
279             case DATALINK_DIAL:
280             case DATALINK_LOGIN:
281               LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
282               dl->state = DATALINK_HANGUP;
283               modem_Offline(dl->physical);
284               chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
285               break;
286           }
287           break;
288       }
289       break;
290 
291     case DATALINK_READY:
292     case DATALINK_LCP:
293     case DATALINK_AUTH:
294     case DATALINK_OPEN:
295       result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
296       break;
297   }
298   return result;
299 }
300 
301 static int
302 datalink_IsSet(struct descriptor *d, const fd_set *fdset)
303 {
304   struct datalink *dl = descriptor2datalink(d);
305 
306   switch (dl->state) {
307     case DATALINK_CLOSED:
308     case DATALINK_OPENING:
309       break;
310 
311     case DATALINK_HANGUP:
312     case DATALINK_DIAL:
313     case DATALINK_LOGIN:
314       return descriptor_IsSet(&dl->chat.desc, fdset);
315 
316     case DATALINK_READY:
317     case DATALINK_LCP:
318     case DATALINK_AUTH:
319     case DATALINK_OPEN:
320       return descriptor_IsSet(&dl->physical->desc, fdset);
321   }
322   return 0;
323 }
324 
325 static void
326 datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
327 {
328   struct datalink *dl = descriptor2datalink(d);
329 
330   switch (dl->state) {
331     case DATALINK_CLOSED:
332     case DATALINK_OPENING:
333       break;
334 
335     case DATALINK_HANGUP:
336     case DATALINK_DIAL:
337     case DATALINK_LOGIN:
338       descriptor_Read(&dl->chat.desc, bundle, fdset);
339       break;
340 
341     case DATALINK_READY:
342     case DATALINK_LCP:
343     case DATALINK_AUTH:
344     case DATALINK_OPEN:
345       descriptor_Read(&dl->physical->desc, bundle, fdset);
346       break;
347   }
348 }
349 
350 static void
351 datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
352 {
353   struct datalink *dl = descriptor2datalink(d);
354 
355   switch (dl->state) {
356     case DATALINK_CLOSED:
357     case DATALINK_OPENING:
358       break;
359 
360     case DATALINK_HANGUP:
361     case DATALINK_DIAL:
362     case DATALINK_LOGIN:
363       descriptor_Write(&dl->chat.desc, bundle, fdset);
364       break;
365 
366     case DATALINK_READY:
367     case DATALINK_LCP:
368     case DATALINK_AUTH:
369     case DATALINK_OPEN:
370       descriptor_Write(&dl->physical->desc, bundle, fdset);
371       break;
372   }
373 }
374 
375 static void
376 datalink_ComeDown(struct datalink *dl, int stay)
377 {
378   if (stay) {
379     dl->dial_tries = -1;
380     dl->reconnect_tries = 0;
381   }
382 
383   if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
384     modem_Offline(dl->physical);
385     if (dl->script.run && dl->state != DATALINK_OPENING) {
386       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
387       dl->state = DATALINK_HANGUP;
388       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
389     } else
390       datalink_HangupDone(dl);
391   }
392 }
393 
394 static void
395 datalink_LayerStart(void *v, struct fsm *fp)
396 {
397   /* The given FSM is about to start up ! */
398   struct datalink *dl = (struct datalink *)v;
399 
400   if (fp->proto == PROTO_LCP)
401     (*dl->parent->LayerStart)(dl->parent->object, fp);
402 }
403 
404 static void
405 datalink_LayerUp(void *v, struct fsm *fp)
406 {
407   /* The given fsm is now up */
408   struct datalink *dl = (struct datalink *)v;
409 
410   if (fp->proto == PROTO_LCP) {
411     dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
412     dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
413     if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
414       if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
415         bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
416       LogPrintf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
417                 Auth2Nam(dl->physical->link.lcp.his_auth),
418                 Auth2Nam(dl->physical->link.lcp.want_auth));
419       if (dl->physical->link.lcp.his_auth == PROTO_PAP)
420         StartAuthChallenge(&dl->pap, dl->physical, SendPapChallenge);
421       if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
422         StartAuthChallenge(&dl->chap.auth, dl->physical, SendChapChallenge);
423     } else
424       datalink_AuthOk(dl);
425   }
426 }
427 
428 void
429 datalink_AuthOk(struct datalink *dl)
430 {
431   /* XXX: Connect to another ppp instance HERE */
432 
433   FsmUp(&dl->physical->link.ccp.fsm);
434   FsmOpen(&dl->physical->link.ccp.fsm);
435   dl->state = DATALINK_OPEN;
436   bundle_NewPhase(dl->bundle, PHASE_NETWORK);
437   (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
438 }
439 
440 void
441 datalink_AuthNotOk(struct datalink *dl)
442 {
443   dl->state = DATALINK_LCP;
444   FsmClose(&dl->physical->link.lcp.fsm);
445 }
446 
447 static void
448 datalink_LayerDown(void *v, struct fsm *fp)
449 {
450   /* The given FSM has been told to come down */
451   struct datalink *dl = (struct datalink *)v;
452 
453   if (fp->proto == PROTO_LCP) {
454     switch (dl->state) {
455       case DATALINK_OPEN:
456         FsmDown(&dl->physical->link.ccp.fsm);
457         FsmClose(&dl->physical->link.ccp.fsm);
458         (*dl->parent->LayerDown)(dl->parent->object, fp);
459         /* fall through */
460 
461       case DATALINK_AUTH:
462         StopTimer(&dl->pap.authtimer);
463         StopTimer(&dl->chap.auth.authtimer);
464     }
465     dl->state = DATALINK_LCP;
466   }
467 }
468 
469 static void
470 datalink_LayerFinish(void *v, struct fsm *fp)
471 {
472   /* The given fsm is now down */
473   struct datalink *dl = (struct datalink *)v;
474 
475   if (fp->proto == PROTO_LCP) {
476     FsmDown(fp);	/* Bring us to INITIAL or STARTING */
477     (*dl->parent->LayerFinish)(dl->parent->object, fp);
478     datalink_ComeDown(dl, 0);
479   }
480 }
481 
482 struct datalink *
483 datalink_Create(const char *name, struct bundle *bundle,
484                 const struct fsm_parent *parent, int type)
485 {
486   struct datalink *dl;
487 
488   dl = (struct datalink *)malloc(sizeof(struct datalink));
489   if (dl == NULL)
490     return dl;
491 
492   dl->desc.type = DATALINK_DESCRIPTOR;
493   dl->desc.next = NULL;
494   dl->desc.UpdateSet = datalink_UpdateSet;
495   dl->desc.IsSet = datalink_IsSet;
496   dl->desc.Read = datalink_Read;
497   dl->desc.Write = datalink_Write;
498 
499   dl->state = DATALINK_CLOSED;
500 
501   *dl->cfg.script.dial = '\0';
502   *dl->cfg.script.login = '\0';
503   *dl->cfg.script.hangup = '\0';
504   *dl->cfg.phone.list = '\0';
505   *dl->phone.list = '\0';
506   dl->phone.next = NULL;
507   dl->phone.alt = NULL;
508   dl->phone.chosen = "N/A";
509   dl->script.run = 1;
510   dl->script.packetmode = 1;
511   mp_linkInit(&dl->mp);
512 
513   dl->bundle = bundle;
514   dl->next = NULL;
515 
516   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
517 
518   dl->dial_tries = 0;
519   dl->cfg.dial.max = 1;
520   dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
521   dl->cfg.dial.timeout = DIAL_TIMEOUT;
522 
523   dl->reconnect_tries = 0;
524   dl->cfg.reconnect.max = 0;
525   dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
526 
527   dl->name = strdup(name);
528   dl->parent = parent;
529   dl->fsmp.LayerStart = datalink_LayerStart;
530   dl->fsmp.LayerUp = datalink_LayerUp;
531   dl->fsmp.LayerDown = datalink_LayerDown;
532   dl->fsmp.LayerFinish = datalink_LayerFinish;
533   dl->fsmp.object = dl;
534 
535   authinfo_Init(&dl->pap);
536   authinfo_Init(&dl->chap.auth);
537 
538   if ((dl->physical = modem_Create(dl, type)) == NULL) {
539     free(dl->name);
540     free(dl);
541     return NULL;
542   }
543   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
544 
545   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
546 
547   return dl;
548 }
549 
550 struct datalink *
551 datalink_Clone(struct datalink *odl, const char *name)
552 {
553   struct datalink *dl;
554 
555   dl = (struct datalink *)malloc(sizeof(struct datalink));
556   if (dl == NULL)
557     return dl;
558 
559   dl->desc.type = DATALINK_DESCRIPTOR;
560   dl->desc.next = NULL;
561   dl->desc.UpdateSet = datalink_UpdateSet;
562   dl->desc.IsSet = datalink_IsSet;
563   dl->desc.Read = datalink_Read;
564   dl->desc.Write = datalink_Write;
565 
566   dl->state = DATALINK_CLOSED;
567 
568   memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
569   mp_linkInit(&dl->mp);
570   *dl->phone.list = '\0';
571   dl->bundle = odl->bundle;
572   dl->next = NULL;
573   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
574   dl->dial_tries = 0;
575   dl->reconnect_tries = 0;
576   dl->name = strdup(name);
577   dl->parent = odl->parent;
578   memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
579   authinfo_Init(&dl->pap);
580   dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry;
581 
582   authinfo_Init(&dl->chap.auth);
583   dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry;
584 
585   if ((dl->physical = modem_Create(dl, PHYS_MANUAL)) == NULL) {
586     free(dl->name);
587     free(dl);
588     return NULL;
589   }
590   memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
591   memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
592          sizeof dl->physical->link.lcp.cfg);
593   memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
594          sizeof dl->physical->link.ccp.cfg);
595   memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
596          sizeof dl->physical->async.cfg);
597 
598   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
599 
600   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
601 
602   return dl;
603 }
604 
605 struct datalink *
606 datalink_Destroy(struct datalink *dl)
607 {
608   struct datalink *result;
609 
610   if (dl->state != DATALINK_CLOSED)
611     LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n",
612               datalink_State(dl));
613 
614   result = dl->next;
615   chat_Destroy(&dl->chat);
616   modem_Destroy(dl->physical);
617   free(dl->name);
618   free(dl);
619 
620   return result;
621 }
622 
623 void
624 datalink_Up(struct datalink *dl, int runscripts, int packetmode)
625 {
626   if (dl->physical->type & (PHYS_STDIN|PHYS_DEDICATED))
627     /* Ignore scripts */
628     runscripts = 0;
629 
630   switch (dl->state) {
631     case DATALINK_CLOSED:
632       LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name);
633       if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
634           bundle_Phase(dl->bundle) == PHASE_TERMINATE)
635         bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
636       dl->state = DATALINK_OPENING;
637       dl->reconnect_tries =
638         dl->physical->type == PHYS_STDIN ? 0 : dl->cfg.reconnect.max;
639       dl->dial_tries = dl->cfg.dial.max;
640       dl->script.run = runscripts;
641       dl->script.packetmode = packetmode;
642       break;
643 
644     case DATALINK_OPENING:
645       if (!dl->script.run && runscripts)
646         dl->script.run = 1;
647       /* fall through */
648 
649     case DATALINK_DIAL:
650     case DATALINK_LOGIN:
651     case DATALINK_READY:
652       if (!dl->script.packetmode && packetmode) {
653         dl->script.packetmode = 1;
654         if (dl->state == DATALINK_READY)
655           datalink_LoginDone(dl);
656       }
657       break;
658   }
659 }
660 
661 void
662 datalink_Close(struct datalink *dl, int stay)
663 {
664   /* Please close */
665   switch (dl->state) {
666     case DATALINK_OPEN:
667       FsmDown(&dl->physical->link.ccp.fsm);
668       FsmClose(&dl->physical->link.ccp.fsm);
669       /* fall through */
670 
671     case DATALINK_AUTH:
672     case DATALINK_LCP:
673       FsmClose(&dl->physical->link.lcp.fsm);
674       if (stay) {
675         dl->dial_tries = -1;
676         dl->reconnect_tries = 0;
677       }
678       break;
679 
680     default:
681       datalink_ComeDown(dl, stay);
682   }
683 }
684 
685 void
686 datalink_Down(struct datalink *dl, int stay)
687 {
688   /* Carrier is lost */
689   switch (dl->state) {
690     case DATALINK_OPEN:
691       FsmDown(&dl->physical->link.ccp.fsm);
692       FsmClose(&dl->physical->link.ccp.fsm);
693       /* fall through */
694 
695     case DATALINK_AUTH:
696     case DATALINK_LCP:
697       FsmDown(&dl->physical->link.lcp.fsm);
698       if (stay)
699         FsmClose(&dl->physical->link.lcp.fsm);
700       else
701         FsmOpen(&dl->physical->link.ccp.fsm);
702       /* fall through */
703 
704     default:
705       datalink_ComeDown(dl, stay);
706   }
707 }
708 
709 void
710 datalink_StayDown(struct datalink *dl)
711 {
712   dl->reconnect_tries = 0;
713 }
714 
715 void
716 datalink_Show(struct datalink *dl, struct prompt *prompt)
717 {
718   prompt_Printf(prompt, "Name: %s\n", dl->name);
719   prompt_Printf(prompt, " State:           %s\n", datalink_State(dl));
720 #ifdef HAVE_DES
721   prompt_Printf(arg->prompt, "  Encryption = %s\n",
722                 dl->chap.using_MSChap ? "MSChap" : "MD5" );
723 #endif
724   prompt_Printf(prompt, "\nDefaults:\n");
725   prompt_Printf(prompt, " Phone List:      %s\n", dl->cfg.phone.list);
726   if (dl->cfg.dial.max)
727     prompt_Printf(prompt, " Dial tries:      %d, delay ", dl->cfg.dial.max);
728   else
729     prompt_Printf(prompt, " Dial tries:      infinite, delay ");
730   if (dl->cfg.dial.next_timeout > 0)
731     prompt_Printf(prompt, "%ds/", dl->cfg.dial.next_timeout);
732   else
733     prompt_Printf(prompt, "random/");
734   if (dl->cfg.dial.timeout > 0)
735     prompt_Printf(prompt, "%ds\n", dl->cfg.dial.timeout);
736   else
737     prompt_Printf(prompt, "random\n");
738   prompt_Printf(prompt, " Reconnect tries: %d, delay ", dl->cfg.reconnect.max);
739   if (dl->cfg.reconnect.timeout > 0)
740     prompt_Printf(prompt, "%ds\n", dl->cfg.reconnect.timeout);
741   else
742     prompt_Printf(prompt, "random\n");
743   prompt_Printf(prompt, " Dial Script:     %s\n", dl->cfg.script.dial);
744   prompt_Printf(prompt, " Login Script:    %s\n", dl->cfg.script.login);
745   prompt_Printf(prompt, " Hangup Script:   %s\n", dl->cfg.script.hangup);
746 }
747 
748 int
749 datalink_SetReconnect(struct cmdargs const *arg)
750 {
751   if (arg->argc == 2) {
752     arg->cx->cfg.reconnect.timeout = atoi(arg->argv[0]);
753     arg->cx->cfg.reconnect.max = atoi(arg->argv[1]);
754     return 0;
755   }
756   return -1;
757 }
758 
759 int
760 datalink_SetRedial(struct cmdargs const *arg)
761 {
762   int timeout;
763   int tries;
764   char *dot;
765 
766   if (arg->argc == 1 || arg->argc == 2) {
767     if (strncasecmp(arg->argv[0], "random", 6) == 0 &&
768 	(arg->argv[0][6] == '\0' || arg->argv[0][6] == '.')) {
769       arg->cx->cfg.dial.timeout = -1;
770       randinit();
771     } else {
772       timeout = atoi(arg->argv[0]);
773 
774       if (timeout >= 0)
775 	arg->cx->cfg.dial.timeout = timeout;
776       else {
777 	LogPrintf(LogWARN, "Invalid redial timeout\n");
778 	return -1;
779       }
780     }
781 
782     dot = strchr(arg->argv[0], '.');
783     if (dot) {
784       if (strcasecmp(++dot, "random") == 0) {
785 	arg->cx->cfg.dial.next_timeout = -1;
786 	randinit();
787       } else {
788 	timeout = atoi(dot);
789 	if (timeout >= 0)
790 	  arg->cx->cfg.dial.next_timeout = timeout;
791 	else {
792 	  LogPrintf(LogWARN, "Invalid next redial timeout\n");
793 	  return -1;
794 	}
795       }
796     } else
797       /* Default next timeout */
798       arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
799 
800     if (arg->argc == 2) {
801       tries = atoi(arg->argv[1]);
802 
803       if (tries >= 0) {
804 	arg->cx->cfg.dial.max = tries;
805       } else {
806 	LogPrintf(LogWARN, "Invalid retry value\n");
807 	return 1;
808       }
809     }
810     return 0;
811   }
812   return -1;
813 }
814 
815 static char *states[] = {
816   "closed",
817   "opening",
818   "hangup",
819   "dial",
820   "login",
821   "ready",
822   "lcp",
823   "auth",
824   "open"
825 };
826 
827 static const char *
828 datalink_State(struct datalink *dl)
829 {
830   if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
831     return "unknown";
832   return states[dl->state];
833 }
834