xref: /freebsd/usr.sbin/ppp/datalink.c (revision 2764b86afdc99a30f4b1a4da2c04db8aa7aa785d)
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.34 1998/04/06 09:12:26 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 "datalink.h"
67 
68 static const char *datalink_State(struct datalink *);
69 
70 static void
71 datalink_OpenTimeout(void *v)
72 {
73   struct datalink *dl = (struct datalink *)v;
74 
75   StopTimer(&dl->dial_timer);
76   if (dl->state == DATALINK_OPENING)
77     LogPrintf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
78 }
79 
80 static void
81 datalink_StartDialTimer(struct datalink *dl, int Timeout)
82 {
83   StopTimer(&dl->dial_timer);
84 
85   if (Timeout) {
86     dl->dial_timer.state = TIMER_STOPPED;
87     if (Timeout > 0)
88       dl->dial_timer.load = Timeout * SECTICKS;
89     else
90       dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
91     dl->dial_timer.func = datalink_OpenTimeout;
92     dl->dial_timer.name = "dial";
93     dl->dial_timer.arg = dl;
94     StartTimer(&dl->dial_timer);
95     if (dl->state == DATALINK_OPENING)
96       LogPrintf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
97                 dl->name, Timeout);
98   }
99 }
100 
101 static void
102 datalink_HangupDone(struct datalink *dl)
103 {
104   modem_Close(dl->physical);
105   dl->phone.chosen = "[N/A]";
106 
107   if (dl->bundle->CleaningUp ||
108       (mode & MODE_DIRECT) ||
109       ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) &&
110        !(mode & (MODE_DDIAL|MODE_DEDICATED)))) {
111     LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
112     dl->state = DATALINK_CLOSED;
113     dl->dial_tries = -1;
114     dl->reconnect_tries = 0;
115     bundle_LinkClosed(dl->bundle, dl);
116     if (!dl->bundle->CleaningUp)
117       datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
118   } else {
119     LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name);
120     dl->state = DATALINK_OPENING;
121     if (dl->dial_tries < 0) {
122       datalink_StartDialTimer(dl, dl->cfg.reconnect_timeout);
123       dl->dial_tries = dl->cfg.max_dial;
124       dl->reconnect_tries--;
125     } else {
126       if (dl->phone.next == NULL)
127         datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
128       else
129         datalink_StartDialTimer(dl, dl->cfg.dial_next_timeout);
130     }
131   }
132 }
133 
134 static const char *
135 datalink_ChoosePhoneNumber(struct datalink *dl)
136 {
137   char *phone;
138 
139   if (dl->phone.alt == NULL) {
140     if (dl->phone.next == NULL) {
141       strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
142       dl->phone.list[sizeof dl->phone.list - 1] = '\0';
143       dl->phone.next = dl->phone.list;
144     }
145     dl->phone.alt = strsep(&dl->phone.next, ":");
146   }
147   phone = strsep(&dl->phone.alt, "|");
148   dl->phone.chosen = *phone ? phone : "[NONE]";
149   if (*phone)
150     LogPrintf(LogPHASE, "Phone: %s\n", phone);
151   return phone;
152 }
153 
154 static void
155 datalink_LoginDone(struct datalink *dl)
156 {
157   if (!dl->script.packetmode) {
158     dl->dial_tries = -1;
159     LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name);
160     dl->state = DATALINK_READY;
161   } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
162     dl->dial_tries = 0;
163     LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n");
164     if (dl->script.run) {
165       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
166       dl->state = DATALINK_HANGUP;
167       modem_Offline(dl->physical);
168       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
169     } else
170       datalink_HangupDone(dl);
171   } else {
172     dl->dial_tries = -1;
173 
174     hdlc_Init(&dl->physical->hdlc);
175     async_Init(&dl->physical->async);
176 
177     lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
178               0 : dl->physical->link.lcp.cfg.openmode);
179     ccp_Setup(&dl->physical->link.ccp);
180 
181     LogPrintf(LogPHASE, "%s: Entering LCP state\n", dl->name);
182     dl->state = DATALINK_LCP;
183     FsmUp(&dl->physical->link.lcp.fsm);
184     FsmOpen(&dl->physical->link.lcp.fsm);
185   }
186 }
187 
188 static int
189 datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
190                    int *n)
191 {
192   struct datalink *dl = descriptor2datalink(d);
193   int result;
194 
195   result = 0;
196   switch (dl->state) {
197     case DATALINK_CLOSED:
198       break;
199 
200     case DATALINK_OPENING:
201       if (dl->dial_timer.state != TIMER_RUNNING) {
202         if (--dl->dial_tries < 0)
203           dl->dial_tries = 0;
204         if (modem_Open(dl->physical, dl->bundle) >= 0) {
205           if (dl->script.run) {
206             LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name);
207             dl->state = DATALINK_DIAL;
208             chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
209                       datalink_ChoosePhoneNumber(dl));
210             if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
211               LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n",
212                         dl->name, dl->cfg.max_dial - dl->dial_tries,
213                         dl->cfg.max_dial);
214           } else
215             datalink_LoginDone(dl);
216         } else {
217           if (!(mode & MODE_DDIAL) && dl->cfg.max_dial)
218             LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
219                       dl->cfg.max_dial - dl->dial_tries, dl->cfg.max_dial);
220           else
221             LogPrintf(LogCHAT, "Failed to open modem\n");
222 
223           if (dl->bundle->CleaningUp ||
224               (!(mode & (MODE_DDIAL|MODE_DEDICATED)) &&
225                dl->cfg.max_dial && dl->dial_tries == 0)) {
226             LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name);
227             dl->state = DATALINK_CLOSED;
228             dl->reconnect_tries = 0;
229             dl->dial_tries = -1;
230             bundle_LinkClosed(dl->bundle, dl);
231           }
232           if (!dl->bundle->CleaningUp)
233             datalink_StartDialTimer(dl, dl->cfg.dial_timeout);
234         }
235       }
236       break;
237 
238     case DATALINK_HANGUP:
239     case DATALINK_DIAL:
240     case DATALINK_LOGIN:
241       result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
242       switch (dl->chat.state) {
243         case CHAT_DONE:
244           /* script succeeded */
245           switch(dl->state) {
246             case DATALINK_HANGUP:
247               datalink_HangupDone(dl);
248               break;
249             case DATALINK_DIAL:
250               LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name);
251               dl->state = DATALINK_LOGIN;
252               chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
253               break;
254             case DATALINK_LOGIN:
255               datalink_LoginDone(dl);
256               break;
257           }
258           break;
259         case CHAT_FAILED:
260           /* Going down - script failed */
261           LogPrintf(LogWARN, "Chat script failed\n");
262           switch(dl->state) {
263             case DATALINK_HANGUP:
264               datalink_HangupDone(dl);
265               break;
266             case DATALINK_DIAL:
267             case DATALINK_LOGIN:
268               LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
269               dl->state = DATALINK_HANGUP;
270               modem_Offline(dl->physical);
271               chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
272               break;
273           }
274           break;
275       }
276       break;
277 
278     case DATALINK_READY:
279     case DATALINK_LCP:
280     case DATALINK_AUTH:
281     case DATALINK_OPEN:
282       result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
283       break;
284   }
285   return result;
286 }
287 
288 static int
289 datalink_IsSet(struct descriptor *d, const fd_set *fdset)
290 {
291   struct datalink *dl = descriptor2datalink(d);
292 
293   switch (dl->state) {
294     case DATALINK_CLOSED:
295     case DATALINK_OPENING:
296       break;
297 
298     case DATALINK_HANGUP:
299     case DATALINK_DIAL:
300     case DATALINK_LOGIN:
301       return descriptor_IsSet(&dl->chat.desc, fdset);
302 
303     case DATALINK_READY:
304     case DATALINK_LCP:
305     case DATALINK_AUTH:
306     case DATALINK_OPEN:
307       return descriptor_IsSet(&dl->physical->desc, fdset);
308   }
309   return 0;
310 }
311 
312 static void
313 datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
314 {
315   struct datalink *dl = descriptor2datalink(d);
316 
317   switch (dl->state) {
318     case DATALINK_CLOSED:
319     case DATALINK_OPENING:
320       break;
321 
322     case DATALINK_HANGUP:
323     case DATALINK_DIAL:
324     case DATALINK_LOGIN:
325       descriptor_Read(&dl->chat.desc, bundle, fdset);
326       break;
327 
328     case DATALINK_READY:
329     case DATALINK_LCP:
330     case DATALINK_AUTH:
331     case DATALINK_OPEN:
332       descriptor_Read(&dl->physical->desc, bundle, fdset);
333       break;
334   }
335 }
336 
337 static void
338 datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
339 {
340   struct datalink *dl = descriptor2datalink(d);
341 
342   switch (dl->state) {
343     case DATALINK_CLOSED:
344     case DATALINK_OPENING:
345       break;
346 
347     case DATALINK_HANGUP:
348     case DATALINK_DIAL:
349     case DATALINK_LOGIN:
350       descriptor_Write(&dl->chat.desc, bundle, fdset);
351       break;
352 
353     case DATALINK_READY:
354     case DATALINK_LCP:
355     case DATALINK_AUTH:
356     case DATALINK_OPEN:
357       descriptor_Write(&dl->physical->desc, bundle, fdset);
358       break;
359   }
360 }
361 
362 static void
363 datalink_ComeDown(struct datalink *dl, int stay)
364 {
365   if (stay) {
366     dl->dial_tries = -1;
367     dl->reconnect_tries = 0;
368   }
369 
370   if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
371     modem_Offline(dl->physical);
372     if (dl->script.run && dl->state != DATALINK_OPENING) {
373       LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name);
374       dl->state = DATALINK_HANGUP;
375       chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
376     } else
377       datalink_HangupDone(dl);
378   }
379 }
380 
381 static void
382 datalink_LayerStart(void *v, struct fsm *fp)
383 {
384   /* The given FSM is about to start up ! */
385   struct datalink *dl = (struct datalink *)v;
386 
387   if (fp->proto == PROTO_LCP)
388     (*dl->parent->LayerStart)(dl->parent->object, fp);
389 }
390 
391 static void
392 datalink_LayerUp(void *v, struct fsm *fp)
393 {
394   /* The given fsm is now up */
395   struct datalink *dl = (struct datalink *)v;
396 
397   if (fp->proto == PROTO_LCP) {
398     dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
399     dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
400     if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
401       if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
402         bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
403       LogPrintf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
404                 Auth2Nam(dl->physical->link.lcp.his_auth),
405                 Auth2Nam(dl->physical->link.lcp.want_auth));
406       if (dl->physical->link.lcp.his_auth == PROTO_PAP)
407         StartAuthChallenge(&dl->pap, dl->physical, SendPapChallenge);
408       if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
409         StartAuthChallenge(&dl->chap.auth, dl->physical, SendChapChallenge);
410     } else
411       datalink_AuthOk(dl);
412   }
413 }
414 
415 void
416 datalink_AuthOk(struct datalink *dl)
417 {
418   /* XXX: Connect to another ppp instance HERE */
419 
420   FsmUp(&dl->physical->link.ccp.fsm);
421   FsmOpen(&dl->physical->link.ccp.fsm);
422   dl->state = DATALINK_OPEN;
423   bundle_NewPhase(dl->bundle, PHASE_NETWORK);
424   (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
425 }
426 
427 void
428 datalink_AuthNotOk(struct datalink *dl)
429 {
430   dl->state = DATALINK_LCP;
431   FsmClose(&dl->physical->link.lcp.fsm);
432 }
433 
434 static void
435 datalink_LayerDown(void *v, struct fsm *fp)
436 {
437   /* The given FSM has been told to come down */
438   struct datalink *dl = (struct datalink *)v;
439 
440   if (fp->proto == PROTO_LCP) {
441     switch (dl->state) {
442       case DATALINK_OPEN:
443         FsmDown(&dl->physical->link.ccp.fsm);
444         FsmClose(&dl->physical->link.ccp.fsm);
445         (*dl->parent->LayerDown)(dl->parent->object, fp);
446         /* fall through */
447 
448       case DATALINK_AUTH:
449         StopTimer(&dl->pap.authtimer);
450         StopTimer(&dl->chap.auth.authtimer);
451     }
452     dl->state = DATALINK_LCP;
453   }
454 }
455 
456 static void
457 datalink_LayerFinish(void *v, struct fsm *fp)
458 {
459   /* The given fsm is now down */
460   struct datalink *dl = (struct datalink *)v;
461 
462   if (fp->proto == PROTO_LCP) {
463     FsmDown(fp);	/* Bring us to INITIAL or STARTING */
464     (*dl->parent->LayerFinish)(dl->parent->object, fp);
465     datalink_ComeDown(dl, 0);
466   }
467 }
468 
469 struct datalink *
470 datalink_Create(const char *name, struct bundle *bundle,
471                 const struct fsm_parent *parent)
472 {
473   struct datalink *dl;
474 
475   dl = (struct datalink *)malloc(sizeof(struct datalink));
476   if (dl == NULL)
477     return dl;
478 
479   dl->desc.type = DATALINK_DESCRIPTOR;
480   dl->desc.next = NULL;
481   dl->desc.UpdateSet = datalink_UpdateSet;
482   dl->desc.IsSet = datalink_IsSet;
483   dl->desc.Read = datalink_Read;
484   dl->desc.Write = datalink_Write;
485 
486   dl->state = DATALINK_CLOSED;
487 
488   *dl->cfg.script.dial = '\0';
489   *dl->cfg.script.login = '\0';
490   *dl->cfg.script.hangup = '\0';
491   *dl->cfg.phone.list = '\0';
492   *dl->phone.list = '\0';
493   dl->phone.next = NULL;
494   dl->phone.alt = NULL;
495   dl->phone.chosen = "N/A";
496   dl->script.run = 1;
497   dl->script.packetmode = 1;
498   mp_linkInit(&dl->mp);
499 
500   dl->bundle = bundle;
501   dl->next = NULL;
502 
503   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
504 
505   dl->dial_tries = 0;
506   dl->cfg.max_dial = 1;
507   dl->cfg.dial_timeout = DIAL_TIMEOUT;
508   dl->cfg.dial_next_timeout = DIAL_NEXT_TIMEOUT;
509 
510   dl->reconnect_tries = 0;
511   dl->cfg.max_reconnect = 0;
512   dl->cfg.reconnect_timeout = RECONNECT_TIMEOUT;
513 
514   dl->name = strdup(name);
515   dl->parent = parent;
516   dl->fsmp.LayerStart = datalink_LayerStart;
517   dl->fsmp.LayerUp = datalink_LayerUp;
518   dl->fsmp.LayerDown = datalink_LayerDown;
519   dl->fsmp.LayerFinish = datalink_LayerFinish;
520   dl->fsmp.object = dl;
521 
522   authinfo_Init(&dl->pap);
523   authinfo_Init(&dl->chap.auth);
524 
525   if ((dl->physical = modem_Create(dl)) == NULL) {
526     free(dl->name);
527     free(dl);
528     return NULL;
529   }
530   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
531 
532   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
533 
534   return dl;
535 }
536 
537 struct datalink *
538 datalink_Clone(struct datalink *odl, const char *name)
539 {
540   struct datalink *dl;
541 
542   dl = (struct datalink *)malloc(sizeof(struct datalink));
543   if (dl == NULL)
544     return dl;
545 
546   dl->desc.type = DATALINK_DESCRIPTOR;
547   dl->desc.next = NULL;
548   dl->desc.UpdateSet = datalink_UpdateSet;
549   dl->desc.IsSet = datalink_IsSet;
550   dl->desc.Read = datalink_Read;
551   dl->desc.Write = datalink_Write;
552 
553   dl->state = DATALINK_CLOSED;
554 
555   memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
556   mp_linkInit(&dl->mp);
557   *dl->phone.list = '\0';
558   dl->bundle = odl->bundle;
559   dl->next = NULL;
560   memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
561   dl->dial_tries = 0;
562   dl->reconnect_tries = 0;
563   dl->name = strdup(name);
564   dl->parent = odl->parent;
565   memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
566   authinfo_Init(&dl->pap);
567   dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry;
568 
569   authinfo_Init(&dl->chap.auth);
570   dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry;
571 
572   if ((dl->physical = modem_Create(dl)) == NULL) {
573     free(dl->name);
574     free(dl);
575     return NULL;
576   }
577   memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
578   memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
579          sizeof dl->physical->link.lcp.cfg);
580   memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
581          sizeof dl->physical->link.ccp.cfg);
582   memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
583          sizeof dl->physical->async.cfg);
584 
585   chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
586 
587   LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name);
588 
589   return dl;
590 }
591 
592 struct datalink *
593 datalink_Destroy(struct datalink *dl)
594 {
595   struct datalink *result;
596 
597   if (dl->state != DATALINK_CLOSED)
598     LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n",
599               datalink_State(dl));
600 
601   result = dl->next;
602   chat_Destroy(&dl->chat);
603   modem_Destroy(dl->physical);
604   free(dl->name);
605   free(dl);
606 
607   return result;
608 }
609 
610 void
611 datalink_Up(struct datalink *dl, int runscripts, int packetmode)
612 {
613   switch (dl->state) {
614     case DATALINK_CLOSED:
615       LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name);
616       if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
617           bundle_Phase(dl->bundle) == PHASE_TERMINATE)
618         bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
619       dl->state = DATALINK_OPENING;
620       dl->reconnect_tries = dl->cfg.max_reconnect;
621       dl->dial_tries = dl->cfg.max_dial;
622       dl->script.run = runscripts;
623       dl->script.packetmode = packetmode;
624       break;
625 
626     case DATALINK_OPENING:
627       if (!dl->script.run && runscripts)
628         dl->script.run = 1;
629       /* fall through */
630 
631     case DATALINK_DIAL:
632     case DATALINK_LOGIN:
633     case DATALINK_READY:
634       if (!dl->script.packetmode && packetmode) {
635         dl->script.packetmode = 1;
636         if (dl->state == DATALINK_READY)
637           datalink_LoginDone(dl);
638       }
639       break;
640   }
641 }
642 
643 void
644 datalink_Close(struct datalink *dl, int stay)
645 {
646   /* Please close */
647   switch (dl->state) {
648     case DATALINK_OPEN:
649       FsmDown(&dl->physical->link.ccp.fsm);
650       FsmClose(&dl->physical->link.ccp.fsm);
651       /* fall through */
652 
653     case DATALINK_AUTH:
654     case DATALINK_LCP:
655       FsmClose(&dl->physical->link.lcp.fsm);
656       if (stay) {
657         dl->dial_tries = -1;
658         dl->reconnect_tries = 0;
659       }
660       break;
661 
662     default:
663       datalink_ComeDown(dl, stay);
664   }
665 }
666 
667 void
668 datalink_Down(struct datalink *dl, int stay)
669 {
670   /* Carrier is lost */
671   switch (dl->state) {
672     case DATALINK_OPEN:
673       FsmDown(&dl->physical->link.ccp.fsm);
674       FsmClose(&dl->physical->link.ccp.fsm);
675       /* fall through */
676 
677     case DATALINK_AUTH:
678     case DATALINK_LCP:
679       FsmDown(&dl->physical->link.lcp.fsm);
680       if (stay)
681         FsmClose(&dl->physical->link.lcp.fsm);
682       else
683         FsmOpen(&dl->physical->link.ccp.fsm);
684       /* fall through */
685 
686     default:
687       datalink_ComeDown(dl, stay);
688   }
689 }
690 
691 void
692 datalink_StayDown(struct datalink *dl)
693 {
694   dl->reconnect_tries = 0;
695 }
696 
697 void
698 datalink_Show(struct datalink *dl, struct prompt *prompt)
699 {
700   prompt_Printf(prompt, "Link %s: State %s\n", dl->name, datalink_State(dl));
701 #ifdef HAVE_DES
702   prompt_Printf(arg->prompt, "  Encryption = %s\n",
703                 dl->chap.using_MSChap ? "MSChap" : "MD5" );
704 #endif
705 }
706 
707 static char *states[] = {
708   "CLOSED",
709   "OPENING",
710   "HANGUP",
711   "DIAL",
712   "LOGIN",
713   "READY",
714   "LCP"
715   "AUTH"
716   "OPEN"
717 };
718 
719 static const char *
720 datalink_State(struct datalink *dl)
721 {
722   if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
723     return "unknown";
724   return states[dl->state];
725 }
726