datalink.c revision 42905
1126304Smtm/*-
2107143Sgordon * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3126304Smtm * All rights reserved.
4107143Sgordon *
5107143Sgordon * Redistribution and use in source and binary forms, with or without
6107143Sgordon * modification, are permitted provided that the following conditions
7107143Sgordon * are met:
8107143Sgordon * 1. Redistributions of source code must retain the above copyright
9107143Sgordon *    notice, this list of conditions and the following disclaimer.
10107143Sgordon * 2. Redistributions in binary form must reproduce the above copyright
11107143Sgordon *    notice, this list of conditions and the following disclaimer in the
12107143Sgordon *    documentation and/or other materials provided with the distribution.
13107143Sgordon *
14107143Sgordon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15107143Sgordon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16107143Sgordon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17107143Sgordon * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18107143Sgordon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19107143Sgordon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20107143Sgordon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21107143Sgordon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22107143Sgordon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23107143Sgordon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24107143Sgordon * SUCH DAMAGE.
25107143Sgordon *
26107143Sgordon *	$Id: datalink.c,v 1.24 1999/01/12 21:50:20 brian Exp $
27107143Sgordon */
28107143Sgordon
29107143Sgordon#include <sys/types.h>
30131866Sru#include <netinet/in.h>
31131866Sru#include <netinet/in_systm.h>
32364008S0mp#include <netinet/ip.h>
33107143Sgordon#include <sys/un.h>
34107143Sgordon
35107143Sgordon#include <ctype.h>
36107143Sgordon#include <stdio.h>
37107143Sgordon#include <stdlib.h>
38107143Sgordon#include <string.h>
39131866Sru#include <sys/uio.h>
40107143Sgordon#include <termios.h>
41131866Sru
42131866Sru#include "mbuf.h"
43107143Sgordon#include "log.h"
44107143Sgordon#include "defs.h"
45107143Sgordon#include "timer.h"
46107143Sgordon#include "fsm.h"
47107143Sgordon#include "lcp.h"
48107143Sgordon#include "descriptor.h"
49107143Sgordon#include "lqr.h"
50107143Sgordon#include "hdlc.h"
51107143Sgordon#include "async.h"
52107143Sgordon#include "throughput.h"
53107143Sgordon#include "ccp.h"
54107143Sgordon#include "link.h"
55107143Sgordon#include "physical.h"
56107143Sgordon#include "iplist.h"
57107143Sgordon#include "slcompress.h"
58107143Sgordon#include "ipcp.h"
59107143Sgordon#include "filter.h"
60159828Syar#include "mp.h"
61159828Syar#include "bundle.h"
62159367Sflz#include "chat.h"
63107143Sgordon#include "auth.h"
64159367Sflz#include "modem.h"
65157473Sflz#include "prompt.h"
66107143Sgordon#include "lcpproto.h"
67107143Sgordon#include "pap.h"
68131866Sru#include "chap.h"
69107143Sgordon#include "command.h"
70131866Sru#include "cbcp.h"
71107143Sgordon#include "datalink.h"
72107143Sgordon
73107143Sgordonstatic void datalink_LoginDone(struct datalink *);
74107143Sgordonstatic void datalink_NewState(struct datalink *, int);
75107143Sgordon
76131866Srustatic void
77107143Sgordondatalink_OpenTimeout(void *v)
78107143Sgordon{
79107143Sgordon  struct datalink *dl = (struct datalink *)v;
80107143Sgordon
81131866Sru  timer_Stop(&dl->dial_timer);
82107143Sgordon  if (dl->state == DATALINK_OPENING)
83131866Sru    log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name);
84107143Sgordon}
85107143Sgordon
86107143Sgordonstatic void
87107143Sgordondatalink_StartDialTimer(struct datalink *dl, int Timeout)
88107143Sgordon{
89107143Sgordon  timer_Stop(&dl->dial_timer);
90107143Sgordon
91107143Sgordon  if (Timeout) {
92107143Sgordon    if (Timeout > 0)
93107143Sgordon      dl->dial_timer.load = Timeout * SECTICKS;
94107143Sgordon    else
95203102Semaste      dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS;
96107143Sgordon    dl->dial_timer.func = datalink_OpenTimeout;
97203102Semaste    dl->dial_timer.name = "dial";
98107143Sgordon    dl->dial_timer.arg = dl;
99107143Sgordon    timer_Start(&dl->dial_timer);
100107143Sgordon    if (dl->state == DATALINK_OPENING)
101107143Sgordon      log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n",
102107143Sgordon                dl->name, Timeout);
103131866Sru  }
104107143Sgordon}
105107143Sgordon
106107143Sgordonstatic void
107107143Sgordondatalink_HangupDone(struct datalink *dl)
108107143Sgordon{
109107143Sgordon  if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp &&
110107143Sgordon      physical_GetFD(dl->physical) != -1) {
111131866Sru    /* Don't close our modem if the link is dedicated */
112107143Sgordon    datalink_LoginDone(dl);
113131866Sru    return;
114107143Sgordon  }
115107143Sgordon
116107143Sgordon  modem_Close(dl->physical);
117107143Sgordon  dl->phone.chosen = "N/A";
118107143Sgordon
119107143Sgordon  if (dl->cbcp.required) {
120107143Sgordon    log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone);
121107143Sgordon    dl->cfg.callback.opmask = 0;
122107143Sgordon    strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone,
123131866Sru            sizeof dl->cfg.phone.list - 1);
124107143Sgordon    dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0';
125131866Sru    dl->phone.alt = dl->phone.next = NULL;
126107143Sgordon    dl->reconnect_tries = dl->cfg.reconnect.max;
127131866Sru    dl->dial_tries = dl->cfg.dial.max;
128131866Sru    dl->script.run = 1;
129107143Sgordon    dl->script.packetmode = 1;
130107143Sgordon    if (!physical_SetMode(dl->physical, PHYS_BACKGROUND))
131107143Sgordon      log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n");
132107143Sgordon    bundle_LinksRemoved(dl->bundle);
133107143Sgordon    if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout)
134107143Sgordon      dl->cbcp.fsm.delay = dl->cfg.dial.timeout;
135131866Sru    datalink_StartDialTimer(dl, dl->cbcp.fsm.delay);
136107143Sgordon    cbcp_Down(&dl->cbcp);
137107143Sgordon    datalink_NewState(dl, DATALINK_OPENING);
138107143Sgordon  } else if (dl->bundle->CleaningUp ||
139107143Sgordon      (dl->physical->type == PHYS_DIRECT) ||
140107143Sgordon      ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) &&
141107143Sgordon       !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) {
142107143Sgordon    datalink_NewState(dl, DATALINK_CLOSED);
143107143Sgordon    dl->dial_tries = -1;
144107143Sgordon    dl->reconnect_tries = 0;
145107143Sgordon    bundle_LinkClosed(dl->bundle, dl);
146107143Sgordon    if (!dl->bundle->CleaningUp)
147107143Sgordon      datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
148107143Sgordon  } else {
149131866Sru    datalink_NewState(dl, DATALINK_OPENING);
150107143Sgordon    if (dl->dial_tries < 0) {
151107143Sgordon      datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout);
152107143Sgordon      dl->dial_tries = dl->cfg.dial.max;
153107143Sgordon      dl->reconnect_tries--;
154107143Sgordon    } else {
155107143Sgordon      if (dl->phone.next == NULL)
156107143Sgordon        datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
157107143Sgordon      else
158107143Sgordon        datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout);
159107143Sgordon    }
160107143Sgordon  }
161107143Sgordon}
162107143Sgordon
163107143Sgordonstatic const char *
164107143Sgordondatalink_ChoosePhoneNumber(struct datalink *dl)
165107143Sgordon{
166131866Sru  char *phone;
167131866Sru
168131866Sru  if (dl->phone.alt == NULL) {
169107143Sgordon    if (dl->phone.next == NULL) {
170131866Sru      strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1);
171107143Sgordon      dl->phone.list[sizeof dl->phone.list - 1] = '\0';
172107143Sgordon      dl->phone.next = dl->phone.list;
173107143Sgordon    }
174131866Sru    dl->phone.alt = strsep(&dl->phone.next, ":");
175131866Sru  }
176131866Sru  phone = strsep(&dl->phone.alt, "|");
177107143Sgordon  dl->phone.chosen = *phone ? phone : "[NONE]";
178131866Sru  if (*phone)
179107143Sgordon    log_Printf(LogPHASE, "Phone: %s\n", phone);
180107143Sgordon  return phone;
181107143Sgordon}
182107143Sgordon
183173013Syarstatic void
184173013Syardatalink_LoginDone(struct datalink *dl)
185173013Syar{
186173013Syar  if (!dl->script.packetmode) {
187173013Syar    dl->dial_tries = -1;
188131866Sru    datalink_NewState(dl, DATALINK_READY);
189107143Sgordon  } else if (modem_Raw(dl->physical, dl->bundle) < 0) {
190107143Sgordon    dl->dial_tries = 0;
191107143Sgordon    log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n");
192107143Sgordon    if (dl->script.run) {
193107143Sgordon      datalink_NewState(dl, DATALINK_HANGUP);
194126304Smtm      modem_Offline(dl->physical);
195107143Sgordon      chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
196107143Sgordon    } else {
197107143Sgordon      timer_Stop(&dl->physical->Timer);
198107143Sgordon      if (dl->physical->type == PHYS_DEDICATED)
199151686Syar        /* force a redial timeout */
200131866Sru        modem_Close(dl->physical);
201131866Sru      datalink_HangupDone(dl);
202131866Sru    }
203107143Sgordon  } else {
204107143Sgordon    dl->dial_tries = -1;
205107143Sgordon
206107143Sgordon    hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp);
207107143Sgordon    async_Init(&dl->physical->async);
208107143Sgordon
209107143Sgordon    lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ?
210107143Sgordon              0 : dl->physical->link.lcp.cfg.openmode);
211107143Sgordon    ccp_Setup(&dl->physical->link.ccp);
212107143Sgordon
213107143Sgordon    datalink_NewState(dl, DATALINK_LCP);
214107143Sgordon    fsm_Up(&dl->physical->link.lcp.fsm);
215107143Sgordon    fsm_Open(&dl->physical->link.lcp.fsm);
216107143Sgordon  }
217131866Sru}
218107143Sgordon
219107143Sgordonstatic int
220107143Sgordondatalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
221107143Sgordon                   int *n)
222108317Sschweikh{
223107143Sgordon  struct datalink *dl = descriptor2datalink(d);
224131866Sru  int result;
225107143Sgordon
226131866Sru  result = 0;
227107143Sgordon  switch (dl->state) {
228107143Sgordon    case DATALINK_CLOSED:
229107143Sgordon      if ((dl->physical->type &
230131530Sru           (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) &&
231131530Sru          !bundle_IsDead(dl->bundle))
232107143Sgordon        /*
233107143Sgordon         * Our first time in - DEDICATED & DDIAL never come down, and
234107143Sgordon         * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED.
235131866Sru         * Go to DATALINK_OPENING via datalink_Up() and fall through.
236131866Sru         */
237107143Sgordon        datalink_Up(dl, 1, 1);
238131866Sru      else
239107143Sgordon        break;
240107143Sgordon      /* fall through */
241107143Sgordon
242107143Sgordon    case DATALINK_OPENING:
243131866Sru      if (dl->dial_timer.state != TIMER_RUNNING) {
244107143Sgordon        if (--dl->dial_tries < 0)
245107143Sgordon          dl->dial_tries = 0;
246107143Sgordon        if (modem_Open(dl->physical, dl->bundle) >= 0) {
247107143Sgordon          log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n"
248131866Sru                           "Type `~?' for help\r\n", dl->name,
249107143Sgordon                           dl->physical->name.full);
250131866Sru          if (dl->script.run) {
251107143Sgordon            datalink_NewState(dl, DATALINK_DIAL);
252107143Sgordon            chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1,
253180628Slme                      datalink_ChoosePhoneNumber(dl));
254107143Sgordon            if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
255107143Sgordon                dl->cfg.dial.max)
256131530Sru              log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n",
257131530Sru                        dl->name, dl->cfg.dial.max - dl->dial_tries,
258107143Sgordon                        dl->cfg.dial.max);
259107143Sgordon          } else
260131866Sru            datalink_LoginDone(dl);
261363727S0mp          return datalink_UpdateSet(d, r, w, e, n);
262363727S0mp        } else {
263363732S0mp          if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
264363727S0mp              dl->cfg.dial.max)
265363732S0mp            log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
266363727S0mp                       dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max);
267363727S0mp          else
268107143Sgordon            log_Printf(LogCHAT, "Failed to open modem\n");
269131530Sru
270131530Sru          if (dl->bundle->CleaningUp ||
271107143Sgordon              (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) &&
272107143Sgordon               dl->cfg.dial.max && dl->dial_tries == 0)) {
273107143Sgordon            datalink_NewState(dl, DATALINK_CLOSED);
274131866Sru            dl->reconnect_tries = 0;
275107143Sgordon            dl->dial_tries = -1;
276107143Sgordon            log_WritePrompts(dl, "Failed to open %s\n",
277107143Sgordon                             dl->physical->name.full);
278107143Sgordon            bundle_LinkClosed(dl->bundle, dl);
279131866Sru          }
280107143Sgordon          if (!dl->bundle->CleaningUp) {
281131866Sru            log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n",
282107143Sgordon                             dl->physical->name.full, dl->cfg.dial.timeout);
283108317Sschweikh            datalink_StartDialTimer(dl, dl->cfg.dial.timeout);
284107143Sgordon          }
285107143Sgordon        }
286107143Sgordon      }
287107143Sgordon      break;
288131866Sru
289159828Syar    case DATALINK_HANGUP:
290159828Syar    case DATALINK_DIAL:
291159828Syar    case DATALINK_LOGIN:
292159828Syar      result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n);
293159828Syar      switch (dl->chat.state) {
294159828Syar        case CHAT_DONE:
295159828Syar          /* script succeeded */
296159828Syar          chat_Destroy(&dl->chat);
297159828Syar          switch(dl->state) {
298159828Syar            case DATALINK_HANGUP:
299159828Syar              datalink_HangupDone(dl);
300159828Syar              break;
301159828Syar            case DATALINK_DIAL:
302159828Syar              datalink_NewState(dl, DATALINK_LOGIN);
303159367Sflz              chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL);
304107143Sgordon              return datalink_UpdateSet(d, r, w, e, n);
305159367Sflz            case DATALINK_LOGIN:
306107143Sgordon              dl->phone.alt = NULL;
307107143Sgordon              datalink_LoginDone(dl);
308161530Sflz              return datalink_UpdateSet(d, r, w, e, n);
309107143Sgordon          }
310161530Sflz          break;
311161530Sflz        case CHAT_FAILED:
312161530Sflz          /* Going down - script failed */
313107143Sgordon          log_Printf(LogWARN, "Chat script failed\n");
314107143Sgordon          chat_Destroy(&dl->chat);
315107143Sgordon          switch(dl->state) {
316107143Sgordon            case DATALINK_HANGUP:
317107143Sgordon              datalink_HangupDone(dl);
318159367Sflz              break;
319157473Sflz            case DATALINK_DIAL:
320157473Sflz            case DATALINK_LOGIN:
321157473Sflz              datalink_NewState(dl, DATALINK_HANGUP);
322157473Sflz              modem_Offline(dl->physical);	/* Is this required ? */
323157473Sflz              chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
324159367Sflz              return datalink_UpdateSet(d, r, w, e, n);
325157473Sflz          }
326157473Sflz          break;
327157473Sflz      }
328157473Sflz      break;
329107143Sgordon
330107143Sgordon    case DATALINK_READY:
331107143Sgordon    case DATALINK_LCP:
332107143Sgordon    case DATALINK_AUTH:
333107143Sgordon    case DATALINK_CBCP:
334131866Sru    case DATALINK_OPEN:
335107143Sgordon      result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n);
336107143Sgordon      break;
337131866Sru  }
338107143Sgordon  return result;
339131866Sru}
340107143Sgordon
341107143Sgordonint
342107143Sgordondatalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e)
343107143Sgordon{
344131866Sru  return physical_RemoveFromSet(dl->physical, r, w, e);
345230007Srea}
346131866Sru
347131866Srustatic int
348107143Sgordondatalink_IsSet(struct descriptor *d, const fd_set *fdset)
349107143Sgordon{
350107143Sgordon  struct datalink *dl = descriptor2datalink(d);
351107143Sgordon
352107143Sgordon  switch (dl->state) {
353107143Sgordon    case DATALINK_CLOSED:
354107143Sgordon    case DATALINK_OPENING:
355107143Sgordon      break;
356107143Sgordon
357107143Sgordon    case DATALINK_HANGUP:
358107143Sgordon    case DATALINK_DIAL:
359107143Sgordon    case DATALINK_LOGIN:
360107143Sgordon      return descriptor_IsSet(&dl->chat.desc, fdset);
361107143Sgordon
362107143Sgordon    case DATALINK_READY:
363107143Sgordon    case DATALINK_LCP:
364107143Sgordon    case DATALINK_AUTH:
365131866Sru    case DATALINK_CBCP:
366131866Sru    case DATALINK_OPEN:
367126304Smtm      return descriptor_IsSet(&dl->physical->desc, fdset);
368126304Smtm  }
369126304Smtm  return 0;
370126304Smtm}
371126304Smtm
372126304Smtmstatic void
373126304Smtmdatalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
374126304Smtm{
375126304Smtm  struct datalink *dl = descriptor2datalink(d);
376131866Sru
377126304Smtm  switch (dl->state) {
378126304Smtm    case DATALINK_CLOSED:
379126304Smtm    case DATALINK_OPENING:
380131866Sru      break;
381131866Sru
382126304Smtm    case DATALINK_HANGUP:
383131866Sru    case DATALINK_DIAL:
384126304Smtm    case DATALINK_LOGIN:
385131866Sru      descriptor_Read(&dl->chat.desc, bundle, fdset);
386126304Smtm      break;
387255809Sdes
388255809Sdes    case DATALINK_READY:
389255809Sdes    case DATALINK_LCP:
390131866Sru    case DATALINK_AUTH:
391126304Smtm    case DATALINK_CBCP:
392126304Smtm    case DATALINK_OPEN:
393126304Smtm      descriptor_Read(&dl->physical->desc, bundle, fdset);
394126304Smtm      break;
395126304Smtm  }
396107143Sgordon}
397131866Sru
398107143Sgordonstatic int
399131866Srudatalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
400126304Smtm{
401131866Sru  struct datalink *dl = descriptor2datalink(d);
402131866Sru  int result = 0;
403126304Smtm
404131866Sru  switch (dl->state) {
405126304Smtm    case DATALINK_CLOSED:
406126304Smtm    case DATALINK_OPENING:
407107143Sgordon      break;
408126304Smtm
409131866Sru    case DATALINK_HANGUP:
410126304Smtm    case DATALINK_DIAL:
411107143Sgordon    case DATALINK_LOGIN:
412107143Sgordon      result = descriptor_Write(&dl->chat.desc, bundle, fdset);
413131866Sru      break;
414131866Sru
415107143Sgordon    case DATALINK_READY:
416107143Sgordon    case DATALINK_LCP:
417131866Sru    case DATALINK_AUTH:
418131866Sru    case DATALINK_CBCP:
419107143Sgordon    case DATALINK_OPEN:
420131866Sru      result = descriptor_Write(&dl->physical->desc, bundle, fdset);
421131866Sru      break;
422131866Sru  }
423107143Sgordon
424131866Sru  return result;
425107143Sgordon}
426131866Sru
427107143Sgordonstatic void
428131866Srudatalink_ComeDown(struct datalink *dl, int how)
429126304Smtm{
430131866Sru  if (how != CLOSE_NORMAL) {
431126304Smtm    dl->dial_tries = -1;
432131866Sru    dl->reconnect_tries = 0;
433131866Sru    if (dl->state >= DATALINK_READY && how == CLOSE_LCP)
434131866Sru      dl->stayonline = 1;
435131866Sru  }
436230007Srea
437230007Srea  if (dl->state >= DATALINK_READY && dl->stayonline) {
438230007Srea    dl->stayonline = 0;
439230007Srea    timer_Stop(&dl->physical->Timer);
440230007Srea    datalink_NewState(dl, DATALINK_READY);
441230007Srea  } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
442230007Srea    modem_Offline(dl->physical);
443230007Srea    chat_Destroy(&dl->chat);
444230007Srea    if (dl->script.run && dl->state != DATALINK_OPENING) {
445230007Srea      datalink_NewState(dl, DATALINK_HANGUP);
446230007Srea      chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL);
447230007Srea    } else
448230007Srea      datalink_HangupDone(dl);
449230007Srea  }
450230007Srea}
451230007Srea
452107143Sgordonstatic void
453107143Sgordondatalink_LayerStart(void *v, struct fsm *fp)
454107143Sgordon{
455107143Sgordon  /* The given FSM is about to start up ! */
456107143Sgordon  struct datalink *dl = (struct datalink *)v;
457131866Sru
458131866Sru  if (fp->proto == PROTO_LCP)
459107143Sgordon    (*dl->parent->LayerStart)(dl->parent->object, fp);
460107143Sgordon}
461131866Sru
462107143Sgordonstatic void
463131866Srudatalink_LayerUp(void *v, struct fsm *fp)
464107143Sgordon{
465107143Sgordon  /* The given fsm is now up */
466107143Sgordon  struct datalink *dl = (struct datalink *)v;
467131866Sru
468107143Sgordon  if (fp->proto == PROTO_LCP) {
469107143Sgordon    datalink_GotAuthname(dl, "", 0);
470131866Sru    dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
471107143Sgordon    dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
472155907Syar    if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
473155907Syar      if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
474131866Sru        bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
475107143Sgordon      log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
476131866Sru                Auth2Nam(dl->physical->link.lcp.his_auth),
477131866Sru                Auth2Nam(dl->physical->link.lcp.want_auth));
478131866Sru      if (dl->physical->link.lcp.his_auth == PROTO_PAP)
479151686Syar        auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge);
480131866Sru      if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
481131866Sru        auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge);
482151686Syar    } else
483107143Sgordon      datalink_AuthOk(dl);
484107143Sgordon  }
485151686Syar}
486131866Sru
487131866Sruvoid
488131866Srudatalink_GotAuthname(struct datalink *dl, const char *name, int len)
489107143Sgordon{
490107143Sgordon  if (len >= sizeof dl->peer.authname)
491131866Sru    len = sizeof dl->peer.authname - 1;
492131866Sru  strncpy(dl->peer.authname, name, len);
493107143Sgordon  dl->peer.authname[len] = '\0';
494131866Sru}
495131866Sru
496107143Sgordonvoid
497107143Sgordondatalink_NCPUp(struct datalink *dl)
498131866Sru{
499151686Syar  int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp);
500131866Sru
501131866Sru  if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) {
502131866Sru    /* we've authenticated in multilink mode ! */
503107143Sgordon    switch (mp_Up(&dl->bundle->ncp.mp, dl)) {
504107143Sgordon      case MP_LINKSENT:
505131866Sru        /* We've handed the link off to another ppp (well, we will soon) ! */
506151686Syar        return;
507131866Sru      case MP_UP:
508131866Sru        /* First link in the bundle */
509131866Sru        auth_Select(dl->bundle, dl->peer.authname);
510107143Sgordon        /* fall through */
511131866Sru      case MP_ADDED:
512107143Sgordon        /* We're in multilink mode ! */
513107143Sgordon        dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE;	/* override */
514131866Sru        break;
515131866Sru      case MP_FAILED:
516107143Sgordon        datalink_AuthNotOk(dl);
517165566Syar        return;
518160615Syar    }
519160615Syar  } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) {
520131866Sru    log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name);
521107143Sgordon    datalink_NewState(dl, DATALINK_OPEN);
522165566Syar    (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
523160615Syar    return;
524160615Syar  } else {
525165566Syar    dl->bundle->ncp.mp.peer = dl->peer;
526165566Syar    ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link);
527165566Syar    auth_Select(dl->bundle, dl->peer.authname);
528165566Syar  }
529165566Syar
530165566Syar  if (ccpok) {
531165566Syar    fsm_Up(&dl->physical->link.ccp.fsm);
532165566Syar    fsm_Open(&dl->physical->link.ccp.fsm);
533165566Syar  }
534165566Syar  datalink_NewState(dl, DATALINK_OPEN);
535165566Syar  bundle_NewPhase(dl->bundle, PHASE_NETWORK);
536165566Syar  (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm);
537165566Syar}
538165566Syar
539165566Syarvoid
540165566Syardatalink_CBCPComplete(struct datalink *dl)
541165566Syar{
542165566Syar  datalink_NewState(dl, DATALINK_LCP);
543165566Syar  fsm_Close(&dl->physical->link.lcp.fsm);
544165566Syar}
545165566Syar
546165566Syarvoid
547165566Syardatalink_CBCPFailed(struct datalink *dl)
548165566Syar{
549165566Syar  cbcp_Down(&dl->cbcp);
550165566Syar  datalink_CBCPComplete(dl);
551165566Syar}
552165566Syar
553131866Sruvoid
554107143Sgordondatalink_AuthOk(struct datalink *dl)
555107143Sgordon{
556107143Sgordon  if ((dl->physical->link.lcp.his_callback.opmask &
557165566Syar       CALLBACK_BIT(CALLBACK_CBCP) ||
558160615Syar       dl->physical->link.lcp.want_callback.opmask &
559160615Syar       CALLBACK_BIT(CALLBACK_CBCP)) &&
560131866Sru      !(dl->physical->link.lcp.want_callback.opmask &
561107143Sgordon        CALLBACK_BIT(CALLBACK_AUTH))) {
562107143Sgordon    /* We must have agreed CBCP if AUTH isn't there any more */
563107143Sgordon    datalink_NewState(dl, DATALINK_CBCP);
564131866Sru    cbcp_Up(&dl->cbcp);
565107143Sgordon  } else if (dl->physical->link.lcp.want_callback.opmask) {
566131866Sru    /* It's not CBCP */
567107143Sgordon    log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name);
568131866Sru    datalink_NewState(dl, DATALINK_LCP);
569107143Sgordon    fsm_Close(&dl->physical->link.lcp.fsm);
570107143Sgordon  } else
571107143Sgordon    switch (dl->physical->link.lcp.his_callback.opmask) {
572131866Sru      case 0:
573107143Sgordon        datalink_NCPUp(dl);
574107143Sgordon        break;
575107143Sgordon
576272974Shrs      case CALLBACK_BIT(CALLBACK_AUTH):
577272974Shrs        auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone,
578272974Shrs                          sizeof dl->cbcp.fsm.phone);
579272974Shrs        if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) {
580272974Shrs          log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name,
581272974Shrs                     dl->peer.authname);
582272974Shrs          *dl->cbcp.fsm.phone = '\0';
583272974Shrs        } else {
584272974Shrs          char *ptr = strchr(dl->cbcp.fsm.phone, ',');
585272974Shrs          if (ptr)
586272974Shrs            *ptr = '\0';	/* Call back on the first number */
587272974Shrs          log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
588272974Shrs                     dl->cbcp.fsm.phone);
589272974Shrs          dl->cbcp.required = 1;
590272974Shrs        }
591272974Shrs        dl->cbcp.fsm.delay = 0;
592131866Sru        datalink_NewState(dl, DATALINK_LCP);
593107143Sgordon        fsm_Close(&dl->physical->link.lcp.fsm);
594131866Sru        break;
595107143Sgordon
596107143Sgordon      case CALLBACK_BIT(CALLBACK_E164):
597107143Sgordon        strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg,
598107143Sgordon                sizeof dl->cbcp.fsm.phone - 1);
599107143Sgordon        dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0';
600107143Sgordon        log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name,
601107143Sgordon                   dl->cbcp.fsm.phone);
602107143Sgordon        dl->cbcp.required = 1;
603107143Sgordon        dl->cbcp.fsm.delay = 0;
604131866Sru        datalink_NewState(dl, DATALINK_LCP);
605107143Sgordon        fsm_Close(&dl->physical->link.lcp.fsm);
606107143Sgordon        break;
607131866Sru
608107143Sgordon      default:
609107143Sgordon        log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n",
610107143Sgordon                   dl->name);
611107143Sgordon        datalink_NewState(dl, DATALINK_LCP);
612295949Saraujo        fsm_Close(&dl->physical->link.lcp.fsm);
613295949Saraujo        break;
614295949Saraujo    }
615295949Saraujo}
616295949Saraujo
617295949Saraujovoid
618295949Saraujodatalink_AuthNotOk(struct datalink *dl)
619295949Saraujo{
620295949Saraujo  datalink_NewState(dl, DATALINK_LCP);
621295949Saraujo  fsm_Close(&dl->physical->link.lcp.fsm);
622155907Syar}
623155907Syar
624155907Syarstatic void
625155907Syardatalink_LayerDown(void *v, struct fsm *fp)
626155907Syar{
627155907Syar  /* The given FSM has been told to come down */
628155907Syar  struct datalink *dl = (struct datalink *)v;
629155907Syar
630155907Syar  if (fp->proto == PROTO_LCP) {
631155907Syar    switch (dl->state) {
632155907Syar      case DATALINK_OPEN:
633155907Syar        peerid_Init(&dl->peer);
634155907Syar        fsm2initial(&dl->physical->link.ccp.fsm);
635131866Sru        datalink_NewState(dl, DATALINK_LCP);  /* before parent TLD */
636107143Sgordon        (*dl->parent->LayerDown)(dl->parent->object, fp);
637131866Sru        /* fall through (just in case) */
638107143Sgordon
639177796Sskv      case DATALINK_CBCP:
640107143Sgordon        if (!dl->cbcp.required)
641131866Sru          cbcp_Down(&dl->cbcp);
642107143Sgordon        /* fall through (just in case) */
643107143Sgordon
644107143Sgordon      case DATALINK_AUTH:
645107143Sgordon        timer_Stop(&dl->pap.authtimer);
646107143Sgordon        timer_Stop(&dl->chap.auth.authtimer);
647107143Sgordon    }
648131866Sru    datalink_NewState(dl, DATALINK_LCP);
649107143Sgordon  }
650131866Sru}
651107143Sgordon
652131866Srustatic void
653107143Sgordondatalink_LayerFinish(void *v, struct fsm *fp)
654131866Sru{
655107143Sgordon  /* The given fsm is now down */
656272974Shrs  struct datalink *dl = (struct datalink *)v;
657272974Shrs
658272974Shrs  if (fp->proto == PROTO_LCP) {
659272974Shrs    fsm2initial(fp);
660272974Shrs    (*dl->parent->LayerFinish)(dl->parent->object, fp);
661272974Shrs    datalink_ComeDown(dl, CLOSE_NORMAL);
662272974Shrs  } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE)
663272974Shrs    fsm_Open(fp);		/* CCP goes to ST_STOPPED */
664131866Sru}
665107143Sgordon
666107143Sgordonstruct datalink *
667131866Srudatalink_Create(const char *name, struct bundle *bundle, int type)
668107143Sgordon{
669131866Sru  struct datalink *dl;
670107143Sgordon
671107143Sgordon  dl = (struct datalink *)malloc(sizeof(struct datalink));
672107143Sgordon  if (dl == NULL)
673107143Sgordon    return dl;
674107143Sgordon
675131866Sru  dl->desc.type = DATALINK_DESCRIPTOR;
676107143Sgordon  dl->desc.UpdateSet = datalink_UpdateSet;
677131866Sru  dl->desc.IsSet = datalink_IsSet;
678107143Sgordon  dl->desc.Read = datalink_Read;
679131866Sru  dl->desc.Write = datalink_Write;
680107143Sgordon
681108317Sschweikh  dl->state = DATALINK_CLOSED;
682107143Sgordon
683131866Sru  *dl->cfg.script.dial = '\0';
684107143Sgordon  *dl->cfg.script.login = '\0';
685131866Sru  *dl->cfg.script.hangup = '\0';
686107143Sgordon  *dl->cfg.phone.list = '\0';
687107143Sgordon  *dl->phone.list = '\0';
688107143Sgordon  dl->phone.next = NULL;
689131866Sru  dl->phone.alt = NULL;
690107143Sgordon  dl->phone.chosen = "N/A";
691131866Sru  dl->stayonline = 0;
692107143Sgordon  dl->script.run = 1;
693107143Sgordon  dl->script.packetmode = 1;
694107143Sgordon  mp_linkInit(&dl->mp);
695107143Sgordon
696107143Sgordon  dl->bundle = bundle;
697107143Sgordon  dl->next = NULL;
698107143Sgordon
699107143Sgordon  memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
700131866Sru
701107143Sgordon  dl->dial_tries = 0;
702131866Sru  dl->cfg.dial.max = 1;
703131866Sru  dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
704107143Sgordon  dl->cfg.dial.timeout = DIAL_TIMEOUT;
705107143Sgordon
706131866Sru  dl->reconnect_tries = 0;
707107143Sgordon  dl->cfg.reconnect.max = 0;
708131866Sru  dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT;
709107143Sgordon
710131866Sru  dl->cfg.callback.opmask = 0;
711107143Sgordon  dl->cfg.cbcp.delay = 0;
712131866Sru  *dl->cfg.cbcp.phone = '\0';
713131866Sru  dl->cfg.cbcp.fsmretry = DEF_FSMRETRY;
714107143Sgordon
715131866Sru  dl->name = strdup(name);
716107143Sgordon  peerid_Init(&dl->peer);
717107143Sgordon  dl->parent = &bundle->fsm;
718107143Sgordon  dl->fsmp.LayerStart = datalink_LayerStart;
719107143Sgordon  dl->fsmp.LayerUp = datalink_LayerUp;
720107143Sgordon  dl->fsmp.LayerDown = datalink_LayerDown;
721131866Sru  dl->fsmp.LayerFinish = datalink_LayerFinish;
722107143Sgordon  dl->fsmp.object = dl;
723107143Sgordon
724107143Sgordon  auth_Init(&dl->pap);
725131866Sru  auth_Init(&dl->chap.auth);
726107143Sgordon
727131866Sru  if ((dl->physical = modem_Create(dl, type)) == NULL) {
728107143Sgordon    free(dl->name);
729131866Sru    free(dl);
730131866Sru    return NULL;
731107143Sgordon  }
732151685Syar  cbcp_Init(&dl->cbcp, dl->physical);
733151685Syar  chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
734151685Syar
735151685Syar  log_Printf(LogPHASE, "%s: Created in %s state\n",
736151685Syar             dl->name, datalink_State(dl));
737151685Syar
738151685Syar  return dl;
739151685Syar}
740151685Syar
741151685Syarstruct datalink *
742131866Srudatalink_Clone(struct datalink *odl, const char *name)
743107143Sgordon{
744131866Sru  struct datalink *dl;
745107143Sgordon
746131866Sru  dl = (struct datalink *)malloc(sizeof(struct datalink));
747107143Sgordon  if (dl == NULL)
748131866Sru    return dl;
749107143Sgordon
750131866Sru  dl->desc.type = DATALINK_DESCRIPTOR;
751107143Sgordon  dl->desc.UpdateSet = datalink_UpdateSet;
752131866Sru  dl->desc.IsSet = datalink_IsSet;
753107143Sgordon  dl->desc.Read = datalink_Read;
754131866Sru  dl->desc.Write = datalink_Write;
755107143Sgordon
756131866Sru  dl->state = DATALINK_CLOSED;
757107143Sgordon
758107143Sgordon  memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg);
759107143Sgordon  mp_linkInit(&dl->mp);
760107143Sgordon  *dl->phone.list = '\0';
761107143Sgordon  dl->phone.next = NULL;
762107143Sgordon  dl->phone.alt = NULL;
763131866Sru  dl->phone.chosen = "N/A";
764107143Sgordon  dl->bundle = odl->bundle;
765107143Sgordon  dl->next = NULL;
766107143Sgordon  memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
767107143Sgordon  dl->dial_tries = 0;
768131866Sru  dl->reconnect_tries = 0;
769107143Sgordon  dl->name = strdup(name);
770107143Sgordon  peerid_Init(&dl->peer);
771107143Sgordon  dl->parent = odl->parent;
772343046Skevans  memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp);
773131866Sru  dl->fsmp.object = dl;
774107143Sgordon  auth_Init(&dl->pap);
775131866Sru  dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry;
776107143Sgordon
777131866Sru  auth_Init(&dl->chap.auth);
778108317Sschweikh  dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry;
779107143Sgordon
780131866Sru  if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) {
781107143Sgordon    free(dl->name);
782107143Sgordon    free(dl);
783107143Sgordon    return NULL;
784131866Sru  }
785107143Sgordon  memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg);
786343046Skevans  memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg,
787343046Skevans         sizeof dl->physical->link.lcp.cfg);
788131866Sru  memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg,
789107143Sgordon         sizeof dl->physical->link.ccp.cfg);
790131866Sru  memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg,
791107143Sgordon         sizeof dl->physical->async.cfg);
792131866Sru
793107143Sgordon  cbcp_Init(&dl->cbcp, dl->physical);
794131866Sru  chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
795107143Sgordon
796131866Sru  log_Printf(LogPHASE, "%s: Cloned in %s state\n",
797107143Sgordon             dl->name, datalink_State(dl));
798131866Sru
799107143Sgordon  return dl;
800107143Sgordon}
801131866Sru
802107143Sgordonstruct datalink *
803107143Sgordondatalink_Destroy(struct datalink *dl)
804107143Sgordon{
805107143Sgordon  struct datalink *result;
806107143Sgordon
807107143Sgordon  if (dl->state != DATALINK_CLOSED) {
808107143Sgordon    log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n",
809107143Sgordon              datalink_State(dl));
810107143Sgordon    switch (dl->state) {
811107143Sgordon      case DATALINK_HANGUP:
812131866Sru      case DATALINK_DIAL:
813131866Sru      case DATALINK_LOGIN:
814131866Sru        chat_Destroy(&dl->chat);	/* Gotta blat the timers ! */
815131866Sru        break;
816131866Sru    }
817131866Sru  }
818131866Sru
819131866Sru  timer_Stop(&dl->dial_timer);
820131866Sru  result = dl->next;
821131866Sru  modem_Destroy(dl->physical);
822131866Sru  free(dl->name);
823131866Sru  free(dl);
824131866Sru
825107143Sgordon  return result;
826107143Sgordon}
827107143Sgordon
828107143Sgordonvoid
829107143Sgordondatalink_Up(struct datalink *dl, int runscripts, int packetmode)
830107143Sgordon{
831107143Sgordon  if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
832107143Sgordon    /* Ignore scripts */
833107143Sgordon    runscripts = 0;
834107143Sgordon
835107143Sgordon  switch (dl->state) {
836107143Sgordon    case DATALINK_CLOSED:
837107143Sgordon      if (bundle_Phase(dl->bundle) == PHASE_DEAD ||
838107143Sgordon          bundle_Phase(dl->bundle) == PHASE_TERMINATE)
839107143Sgordon        bundle_NewPhase(dl->bundle, PHASE_ESTABLISH);
840107143Sgordon      datalink_NewState(dl, DATALINK_OPENING);
841107143Sgordon      dl->reconnect_tries =
842131866Sru        dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max;
843107143Sgordon      dl->dial_tries = dl->cfg.dial.max;
844131866Sru      dl->script.run = runscripts;
845107143Sgordon      dl->script.packetmode = packetmode;
846107143Sgordon      break;
847107143Sgordon
848107143Sgordon    case DATALINK_OPENING:
849107143Sgordon      if (!dl->script.run && runscripts)
850107143Sgordon        dl->script.run = 1;
851107143Sgordon      /* fall through */
852107143Sgordon
853107143Sgordon    case DATALINK_DIAL:
854131866Sru    case DATALINK_LOGIN:
855107143Sgordon    case DATALINK_READY:
856107143Sgordon      if (!dl->script.packetmode && packetmode) {
857107143Sgordon        dl->script.packetmode = 1;
858107143Sgordon        if (dl->state == DATALINK_READY)
859107143Sgordon          datalink_LoginDone(dl);
860107143Sgordon      }
861107143Sgordon      break;
862107143Sgordon  }
863169668Smtm}
864169668Smtm
865169668Smtmvoid
866173013Syardatalink_Close(struct datalink *dl, int how)
867173013Syar{
868364008S0mp  /* Please close */
869364008S0mp  switch (dl->state) {
870364008S0mp    case DATALINK_OPEN:
871364008S0mp      peerid_Init(&dl->peer);
872364008S0mp      fsm2initial(&dl->physical->link.ccp.fsm);
873169668Smtm      /* fall through */
874173013Syar
875173013Syar    case DATALINK_CBCP:
876173013Syar    case DATALINK_AUTH:
877169668Smtm    case DATALINK_LCP:
878173013Syar      fsm_Close(&dl->physical->link.lcp.fsm);
879173013Syar      if (how != CLOSE_NORMAL) {
880173013Syar        dl->dial_tries = -1;
881131866Sru        dl->reconnect_tries = 0;
882107143Sgordon        if (how == CLOSE_LCP)
883107143Sgordon          dl->stayonline = 1;
884131866Sru      }
885107143Sgordon      break;
886107143Sgordon
887107143Sgordon    default:
888107143Sgordon      datalink_ComeDown(dl, how);
889131866Sru  }
890107143Sgordon}
891107143Sgordon
892107143Sgordonvoid
893107143Sgordondatalink_Down(struct datalink *dl, int how)
894107143Sgordon{
895131866Sru  /* Carrier is lost */
896107143Sgordon  switch (dl->state) {
897131866Sru    case DATALINK_OPEN:
898107143Sgordon      peerid_Init(&dl->peer);
899107143Sgordon      fsm2initial(&dl->physical->link.ccp.fsm);
900107143Sgordon      /* fall through */
901107143Sgordon
902131866Sru    case DATALINK_CBCP:
903107143Sgordon    case DATALINK_AUTH:
904107143Sgordon    case DATALINK_LCP:
905107143Sgordon      fsm2initial(&dl->physical->link.lcp.fsm);
906107143Sgordon      /* fall through */
907107143Sgordon
908107143Sgordon    default:
909107143Sgordon      datalink_ComeDown(dl, how);
910107143Sgordon  }
911107143Sgordon}
912107143Sgordon
913131866Sruvoid
914107143Sgordondatalink_StayDown(struct datalink *dl)
915131866Sru{
916107143Sgordon  dl->reconnect_tries = 0;
917107143Sgordon}
918107143Sgordon
919107143Sgordonvoid
920107143Sgordondatalink_DontHangup(struct datalink *dl)
921107143Sgordon{
922131866Sru  if (dl->state >= DATALINK_LCP)
923107143Sgordon    dl->stayonline = 1;
924131866Sru}
925107143Sgordon
926107143Sgordonint
927datalink_Show(struct cmdargs const *arg)
928{
929  prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
930  prompt_Printf(arg->prompt, " State:              %s\n",
931                datalink_State(arg->cx));
932  prompt_Printf(arg->prompt, " CHAP Encryption:    %s\n",
933                arg->cx->chap.using_MSChap ? "MSChap" : "MD5" );
934  prompt_Printf(arg->prompt, " Peer name:          ");
935  if (*arg->cx->peer.authname)
936    prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname);
937  else if (arg->cx->state == DATALINK_OPEN)
938    prompt_Printf(arg->prompt, "None requested\n");
939  else
940    prompt_Printf(arg->prompt, "N/A\n");
941  prompt_Printf(arg->prompt, " Discriminator:      %s\n",
942                mp_Enddisc(arg->cx->peer.enddisc.class,
943                           arg->cx->peer.enddisc.address,
944                           arg->cx->peer.enddisc.len));
945
946  prompt_Printf(arg->prompt, "\nDefaults:\n");
947  prompt_Printf(arg->prompt, " Phone List:         %s\n",
948                arg->cx->cfg.phone.list);
949  if (arg->cx->cfg.dial.max)
950    prompt_Printf(arg->prompt, " Dial tries:         %d, delay ",
951                  arg->cx->cfg.dial.max);
952  else
953    prompt_Printf(arg->prompt, " Dial tries:         infinite, delay ");
954  if (arg->cx->cfg.dial.next_timeout > 0)
955    prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout);
956  else
957    prompt_Printf(arg->prompt, "random/");
958  if (arg->cx->cfg.dial.timeout > 0)
959    prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout);
960  else
961    prompt_Printf(arg->prompt, "random\n");
962  prompt_Printf(arg->prompt, " Reconnect tries:    %d, delay ",
963                arg->cx->cfg.reconnect.max);
964  if (arg->cx->cfg.reconnect.timeout > 0)
965    prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout);
966  else
967    prompt_Printf(arg->prompt, "random\n");
968  prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type ==
969                PHYS_DIRECT ?  "accepted: " : "requested:");
970  if (!arg->cx->cfg.callback.opmask)
971    prompt_Printf(arg->prompt, "none\n");
972  else {
973    int comma = 0;
974
975    if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) {
976      prompt_Printf(arg->prompt, "none");
977      comma = 1;
978    }
979    if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) {
980      prompt_Printf(arg->prompt, "%sauth", comma ? ", " : "");
981      comma = 1;
982    }
983    if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) {
984      prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : "");
985      if (arg->cx->physical->type != PHYS_DIRECT)
986        prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg);
987      comma = 1;
988    }
989    if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) {
990      prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : "");
991      prompt_Printf(arg->prompt, " CBCP:               delay: %ds\n",
992                    arg->cx->cfg.cbcp.delay);
993      prompt_Printf(arg->prompt, "                     phone: ");
994      if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) {
995        if (arg->cx->physical->type & PHYS_DIRECT)
996          prompt_Printf(arg->prompt, "Caller decides\n");
997        else
998          prompt_Printf(arg->prompt, "Dialback server decides\n");
999      } else
1000        prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone);
1001      prompt_Printf(arg->prompt, "                     timeout: %lds\n",
1002                    arg->cx->cfg.cbcp.fsmretry);
1003    } else
1004      prompt_Printf(arg->prompt, "\n");
1005  }
1006
1007  prompt_Printf(arg->prompt, " Dial Script:        %s\n",
1008                arg->cx->cfg.script.dial);
1009  prompt_Printf(arg->prompt, " Login Script:       %s\n",
1010                arg->cx->cfg.script.login);
1011  prompt_Printf(arg->prompt, " Hangup Script:      %s\n",
1012                arg->cx->cfg.script.hangup);
1013  return 0;
1014}
1015
1016int
1017datalink_SetReconnect(struct cmdargs const *arg)
1018{
1019  if (arg->argc == arg->argn+2) {
1020    arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]);
1021    arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]);
1022    return 0;
1023  }
1024  return -1;
1025}
1026
1027int
1028datalink_SetRedial(struct cmdargs const *arg)
1029{
1030  int timeout;
1031  int tries;
1032  char *dot;
1033
1034  if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) {
1035    if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 &&
1036	(arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) {
1037      arg->cx->cfg.dial.timeout = -1;
1038      randinit();
1039    } else {
1040      timeout = atoi(arg->argv[arg->argn]);
1041
1042      if (timeout >= 0)
1043	arg->cx->cfg.dial.timeout = timeout;
1044      else {
1045	log_Printf(LogWARN, "Invalid redial timeout\n");
1046	return -1;
1047      }
1048    }
1049
1050    dot = strchr(arg->argv[arg->argn], '.');
1051    if (dot) {
1052      if (strcasecmp(++dot, "random") == 0) {
1053	arg->cx->cfg.dial.next_timeout = -1;
1054	randinit();
1055      } else {
1056	timeout = atoi(dot);
1057	if (timeout >= 0)
1058	  arg->cx->cfg.dial.next_timeout = timeout;
1059	else {
1060	  log_Printf(LogWARN, "Invalid next redial timeout\n");
1061	  return -1;
1062	}
1063      }
1064    } else
1065      /* Default next timeout */
1066      arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT;
1067
1068    if (arg->argc == arg->argn+2) {
1069      tries = atoi(arg->argv[arg->argn+1]);
1070
1071      if (tries >= 0) {
1072	arg->cx->cfg.dial.max = tries;
1073      } else {
1074	log_Printf(LogWARN, "Invalid retry value\n");
1075	return 1;
1076      }
1077    }
1078    return 0;
1079  }
1080  return -1;
1081}
1082
1083static const char *states[] = {
1084  "closed",
1085  "opening",
1086  "hangup",
1087  "dial",
1088  "login",
1089  "ready",
1090  "lcp",
1091  "auth",
1092  "cbcp",
1093  "open"
1094};
1095
1096const char *
1097datalink_State(struct datalink *dl)
1098{
1099  if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0])
1100    return "unknown";
1101  return states[dl->state];
1102}
1103
1104static void
1105datalink_NewState(struct datalink *dl, int state)
1106{
1107  if (state != dl->state) {
1108    if (state >= 0 && state < sizeof states / sizeof states[0]) {
1109      log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl),
1110                 states[state]);
1111      dl->state = state;
1112    } else
1113      log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state);
1114  }
1115}
1116
1117struct datalink *
1118iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov,
1119             int fd)
1120{
1121  struct datalink *dl, *cdl;
1122  u_int retry;
1123  char *oname;
1124
1125  dl = (struct datalink *)iov[(*niov)++].iov_base;
1126  dl->name = iov[*niov].iov_base;
1127
1128  if (dl->name[DATALINK_MAXNAME-1]) {
1129    dl->name[DATALINK_MAXNAME-1] = '\0';
1130    if (strlen(dl->name) == DATALINK_MAXNAME - 1)
1131      log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name);
1132  }
1133
1134  /* Make sure the name is unique ! */
1135  oname = NULL;
1136  do {
1137    for (cdl = bundle->links; cdl; cdl = cdl->next)
1138      if (!strcasecmp(dl->name, cdl->name)) {
1139        if (oname)
1140          free(datalink_NextName(dl));
1141        else
1142          oname = datalink_NextName(dl);
1143        break;	/* Keep renaming 'till we have no conflicts */
1144      }
1145  } while (cdl);
1146
1147  if (oname) {
1148    log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name);
1149    free(oname);
1150  } else {
1151    dl->name = strdup(dl->name);
1152    free(iov[*niov].iov_base);
1153  }
1154  (*niov)++;
1155
1156  dl->desc.type = DATALINK_DESCRIPTOR;
1157  dl->desc.UpdateSet = datalink_UpdateSet;
1158  dl->desc.IsSet = datalink_IsSet;
1159  dl->desc.Read = datalink_Read;
1160  dl->desc.Write = datalink_Write;
1161
1162  mp_linkInit(&dl->mp);
1163  *dl->phone.list = '\0';
1164  dl->phone.next = NULL;
1165  dl->phone.alt = NULL;
1166  dl->phone.chosen = "N/A";
1167
1168  dl->bundle = bundle;
1169  dl->next = NULL;
1170  memset(&dl->dial_timer, '\0', sizeof dl->dial_timer);
1171  dl->dial_tries = 0;
1172  dl->reconnect_tries = 0;
1173  dl->parent = &bundle->fsm;
1174  dl->fsmp.LayerStart = datalink_LayerStart;
1175  dl->fsmp.LayerUp = datalink_LayerUp;
1176  dl->fsmp.LayerDown = datalink_LayerDown;
1177  dl->fsmp.LayerFinish = datalink_LayerFinish;
1178  dl->fsmp.object = dl;
1179
1180  retry = dl->pap.cfg.fsmretry;
1181  auth_Init(&dl->pap);
1182  dl->pap.cfg.fsmretry = retry;
1183
1184  retry = dl->chap.auth.cfg.fsmretry;
1185  auth_Init(&dl->chap.auth);
1186  dl->chap.auth.cfg.fsmretry = retry;
1187
1188  dl->physical = iov2modem(dl, iov, niov, maxiov, fd);
1189
1190  if (!dl->physical) {
1191    free(dl->name);
1192    free(dl);
1193    dl = NULL;
1194  } else {
1195    cbcp_Init(&dl->cbcp, dl->physical);
1196    chat_Init(&dl->chat, dl->physical, NULL, 1, NULL);
1197
1198    log_Printf(LogPHASE, "%s: Transferred in %s state\n",
1199              dl->name, datalink_State(dl));
1200  }
1201
1202  return dl;
1203}
1204
1205int
1206datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov,
1207             pid_t newpid)
1208{
1209  /* If `dl' is NULL, we're allocating before a Fromiov() */
1210  int link_fd;
1211
1212  if (dl) {
1213    timer_Stop(&dl->dial_timer);
1214    /* The following is purely for the sake of paranoia */
1215    cbcp_Down(&dl->cbcp);
1216    timer_Stop(&dl->pap.authtimer);
1217    timer_Stop(&dl->chap.auth.authtimer);
1218  }
1219
1220  if (*niov >= maxiov - 1) {
1221    log_Printf(LogERROR, "Toiov: No room for datalink !\n");
1222    if (dl) {
1223      free(dl->name);
1224      free(dl);
1225    }
1226    return -1;
1227  }
1228
1229  iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl);
1230  iov[(*niov)++].iov_len = sizeof *dl;
1231  iov[*niov].iov_base =
1232    dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME);
1233  iov[(*niov)++].iov_len = DATALINK_MAXNAME;
1234
1235  link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid);
1236
1237  if (link_fd == -1 && dl) {
1238    free(dl->name);
1239    free(dl);
1240  }
1241
1242  return link_fd;
1243}
1244
1245void
1246datalink_Rename(struct datalink *dl, const char *name)
1247{
1248  free(dl->name);
1249  dl->physical->link.name = dl->name = strdup(name);
1250}
1251
1252char *
1253datalink_NextName(struct datalink *dl)
1254{
1255  int f, n;
1256  char *name, *oname;
1257
1258  n = strlen(dl->name);
1259  name = (char *)malloc(n+3);
1260  for (f = n - 1; f >= 0; f--)
1261    if (!isdigit(dl->name[f]))
1262      break;
1263  n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name);
1264  sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1);
1265  oname = dl->name;
1266  dl->name = name;
1267  /* our physical link name isn't updated (it probably isn't created yet) */
1268  return oname;
1269}
1270
1271int
1272datalink_SetMode(struct datalink *dl, int mode)
1273{
1274  if (!physical_SetMode(dl->physical, mode))
1275    return 0;
1276  if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED))
1277    dl->script.run = 0;
1278  if (dl->physical->type == PHYS_DIRECT)
1279    dl->reconnect_tries = 0;
1280  if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY)
1281    datalink_Up(dl, 1, 1);
1282  return 1;
1283}
1284