cbcp.c revision 42842
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: cbcp.c,v 1.7 1998/10/31 17:38:48 brian Exp $
27 */
28
29#include <sys/types.h>
30
31#include <sys/un.h>
32
33#include <string.h>
34#include <termios.h>
35
36#include "defs.h"
37#include "log.h"
38#include "timer.h"
39#include "descriptor.h"
40#include "lqr.h"
41#include "mbuf.h"
42#include "fsm.h"
43#include "lcp.h"
44#include "throughput.h"
45#include "hdlc.h"
46#include "ccp.h"
47#include "link.h"
48#include "async.h"
49#include "physical.h"
50#include "lcpproto.h"
51#include "cbcp.h"
52#include "mp.h"
53#include "chat.h"
54#include "auth.h"
55#include "chap.h"
56#include "datalink.h"
57
58void
59cbcp_Init(struct cbcp *cbcp, struct physical *p)
60{
61  cbcp->required = 0;
62  cbcp->fsm.state = CBCP_CLOSED;
63  cbcp->fsm.id = 0;
64  cbcp->fsm.delay = 0;
65  *cbcp->fsm.phone = '\0';
66  memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer);
67  cbcp->p = p;
68}
69
70static void cbcp_SendReq(struct cbcp *);
71static void cbcp_SendResponse(struct cbcp *);
72static void cbcp_SendAck(struct cbcp *);
73
74static void
75cbcp_Timeout(void *v)
76{
77  struct cbcp *cbcp = (struct cbcp *)v;
78
79  timer_Stop(&cbcp->fsm.timer);
80  if (cbcp->fsm.restart) {
81    switch (cbcp->fsm.state) {
82      case CBCP_CLOSED:
83      case CBCP_STOPPED:
84        log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
85                   cbcp->p->dl->name);
86        break;
87
88      case CBCP_REQSENT:
89        cbcp_SendReq(cbcp);
90        break;
91      case CBCP_RESPSENT:
92        cbcp_SendResponse(cbcp);
93        break;
94      case CBCP_ACKSENT:
95        cbcp_SendAck(cbcp);
96        break;
97    }
98  } else {
99    const char *missed;
100
101    switch (cbcp->fsm.state) {
102      case CBCP_STOPPED:
103        missed = "REQ";
104        break;
105      case CBCP_REQSENT:
106        missed = "RESPONSE";
107        break;
108      case CBCP_RESPSENT:
109        missed = "ACK";
110        break;
111      case CBCP_ACKSENT:
112        missed = "Terminate REQ";
113        break;
114      default:
115        log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
116                   cbcp->p->dl->name);
117        missed = NULL;
118        break;
119    }
120    if (missed)
121      log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n",
122                 cbcp->p->dl->name, missed);
123    datalink_CBCPFailed(cbcp->p->dl);
124  }
125}
126
127static void
128cbcp_StartTimer(struct cbcp *cbcp, int timeout)
129{
130  timer_Stop(&cbcp->fsm.timer);
131  cbcp->fsm.timer.func = cbcp_Timeout;
132  cbcp->fsm.timer.name = "cbcp";
133  cbcp->fsm.timer.load = timeout * SECTICKS;
134  cbcp->fsm.timer.arg = cbcp;
135  timer_Start(&cbcp->fsm.timer);
136}
137
138#define CBCP_CLOSED	(0)	/* Not in use */
139#define CBCP_STOPPED	(1)	/* Waiting for a REQ */
140#define CBCP_REQSENT	(2)	/* Waiting for a RESP */
141#define CBCP_RESPSENT	(3)	/* Waiting for an ACK */
142#define CBCP_ACKSENT	(4)	/* Waiting for an LCP Term REQ */
143
144static const char *cbcpname[] = {
145  "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
146};
147
148static const char *
149cbcpstate(int s)
150{
151  if (s < sizeof cbcpname / sizeof cbcpname[0])
152    return cbcpname[s];
153  return "???";
154}
155
156static void
157cbcp_NewPhase(struct cbcp *cbcp, int new)
158{
159  if (cbcp->fsm.state != new) {
160    log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name,
161               cbcpstate(cbcp->fsm.state), cbcpstate(new));
162    cbcp->fsm.state = new;
163  }
164}
165
166struct cbcp_header {
167  u_char code;
168  u_char id;
169  u_int16_t length;	/* Network byte order */
170};
171
172
173/* cbcp_header::code values */
174#define CBCP_REQ	(1)
175#define CBCP_RESPONSE	(2)
176#define CBCP_ACK	(3)
177
178struct cbcp_data {
179  u_char type;
180  u_char length;
181  u_char delay;
182  char addr_start[253];	/* max cbcp_data length 255 + 1 for NULL */
183};
184
185/* cbcp_data::type values */
186#define CBCP_NONUM	(1)
187#define CBCP_CLIENTNUM	(2)
188#define CBCP_SERVERNUM	(3)
189#define CBCP_LISTNUM	(4)
190
191static void
192cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data)
193{
194  struct cbcp_header *head;
195  struct mbuf *bp;
196
197  bp = mbuf_Alloc(sizeof *head + data->length, MB_CBCP);
198  head = (struct cbcp_header *)MBUF_CTOP(bp);
199  head->code = code;
200  head->id = cbcp->fsm.id;
201  head->length = htons(sizeof *head + data->length);
202  memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length);
203  log_DumpBp(LogDEBUG, "cbcp_Output", bp);
204  hdlc_Output(&cbcp->p->link, PRI_LINK, PROTO_CBCP, bp);
205}
206
207static const char *
208cbcp_data_Type(int type)
209{
210  static const char *types[] = {
211    "No callback", "User-spec", "Server-spec", "list"
212  };
213
214  if (type < 1 || type > sizeof types / sizeof types[0])
215    return "???";
216  return types[type-1];
217}
218
219struct cbcp_addr {
220  u_char type;
221  char addr[1];		/* Really ASCIIZ */
222};
223
224/* cbcp_data::type values */
225#define CBCP_ADDR_PSTN	(1)
226
227static void
228cbcp_data_Show(struct cbcp_data *data)
229{
230  struct cbcp_addr *addr;
231  char *end;
232
233  addr = (struct cbcp_addr *)data->addr_start;
234  end = (char *)data + data->length;
235  *end = '\0';
236
237  log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type));
238  if ((char *)&data->delay < end) {
239    log_Printf(LogCBCP, " DELAY %d\n", data->delay);
240    while (addr->addr < end) {
241      if (addr->type == CBCP_ADDR_PSTN)
242        log_Printf(LogCBCP, " ADDR %s\n", addr->addr);
243      else
244        log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type);
245      addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
246    }
247  }
248}
249
250static void
251cbcp_SendReq(struct cbcp *cbcp)
252{
253  struct cbcp_data data;
254  struct cbcp_addr *addr;
255  char list[sizeof cbcp->fsm.phone], *next;
256  int len, max;
257
258  /* Only callees send REQs */
259
260  log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name,
261             cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
262  data.type = cbcp->fsm.type;
263  data.delay = 0;
264  strncpy(list, cbcp->fsm.phone, sizeof list - 1);
265  list[sizeof list - 1] = '\0';
266
267  switch (data.type) {
268    case CBCP_CLIENTNUM:
269      addr = (struct cbcp_addr *)data.addr_start;
270      addr->type = CBCP_ADDR_PSTN;
271      *addr->addr = '\0';
272      data.length = addr->addr - (char *)&data;
273      break;
274
275    case CBCP_LISTNUM:
276      addr = (struct cbcp_addr *)data.addr_start;
277      for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
278        len = strlen(next);
279        max = data.addr_start + sizeof data.addr_start - addr->addr - 1;
280        if (len <= max) {
281          addr->type = CBCP_ADDR_PSTN;
282          strcpy(addr->addr, next);
283          addr = (struct cbcp_addr *)((char *)addr + len + 2);
284        } else
285          log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n",
286                     next);
287      }
288      data.length = (char *)addr - (char *)&data;
289      break;
290
291    case CBCP_SERVERNUM:
292      data.length = data.addr_start - (char *)&data;
293      break;
294
295    default:
296      data.length = (char *)&data.delay - (char *)&data;
297      break;
298  }
299
300  cbcp_data_Show(&data);
301  cbcp_Output(cbcp, CBCP_REQ, &data);
302  cbcp->fsm.restart--;
303  cbcp_StartTimer(cbcp, cbcp->fsm.delay);
304  cbcp_NewPhase(cbcp, CBCP_REQSENT);		/* Wait for a RESPONSE */
305}
306
307void
308cbcp_Up(struct cbcp *cbcp)
309{
310  struct lcp *lcp = &cbcp->p->link.lcp;
311
312  cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay;
313  if (*cbcp->p->dl->peer.authname == '\0' ||
314      !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone,
315                         sizeof cbcp->fsm.phone)) {
316    strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone,
317            sizeof cbcp->fsm.phone - 1);
318    cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0';
319  }
320
321  if (lcp->want_callback.opmask) {
322    if (*cbcp->fsm.phone == '\0')
323      cbcp->fsm.type = CBCP_NONUM;
324    else if (!strcmp(cbcp->fsm.phone, "*")) {
325      cbcp->fsm.type = CBCP_SERVERNUM;
326      *cbcp->fsm.phone = '\0';
327    } else
328      cbcp->fsm.type = CBCP_CLIENTNUM;
329    cbcp_NewPhase(cbcp, CBCP_STOPPED);		/* Wait for a REQ */
330    cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_REQs);
331  } else {
332    if (*cbcp->fsm.phone == '\0')
333      cbcp->fsm.type = CBCP_NONUM;
334    else if (!strcmp(cbcp->fsm.phone, "*")) {
335      cbcp->fsm.type = CBCP_CLIENTNUM;
336      *cbcp->fsm.phone = '\0';
337    } else if (strchr(cbcp->fsm.phone, ','))
338      cbcp->fsm.type = CBCP_LISTNUM;
339    else
340      cbcp->fsm.type = CBCP_SERVERNUM;
341    cbcp->fsm.restart = DEF_REQs;
342    cbcp_SendReq(cbcp);
343  }
344}
345
346static int
347cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data)
348{
349  /*
350   * We've received a REQ (data).  Adjust our reponse (cbcp->fsm.*)
351   * so that we (hopefully) agree with the peer
352   */
353  struct cbcp_addr *addr;
354
355  switch (data->type) {
356    case CBCP_NONUM:
357      /*
358       * If the callee offers no callback, we send our desired response
359       * anyway.  This is what Win95 does - although I can't find this
360       * behaviour documented in the spec....
361       */
362      return 1;
363
364    case CBCP_CLIENTNUM:
365      if (cbcp->fsm.type == CBCP_CLIENTNUM) {
366        char *ptr;
367
368        if (data->length > data->addr_start - (char *)data) {
369          /*
370           * The peer has given us an address type spec - make sure we
371           * understand !
372           */
373          addr = (struct cbcp_addr *)data->addr_start;
374          if (addr->type != CBCP_ADDR_PSTN) {
375            log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
376                       (int)addr->type);
377            return 0;
378          }
379        }
380        /* we accept the REQ even if the peer didn't specify an addr->type */
381        ptr = strchr(cbcp->fsm.phone, ',');
382        if (ptr)
383          *ptr = '\0';		/* Just use the first number in our list */
384        return 1;
385      }
386      log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n");
387      return 0;
388
389    case CBCP_SERVERNUM:
390      if (cbcp->fsm.type == CBCP_SERVERNUM) {
391        *cbcp->fsm.phone = '\0';
392        return 1;
393      }
394      if (data->length > data->addr_start - (char *)data) {
395        /*
396         * This violates the spec, but if the peer has told us the
397         * number it wants to call back, take advantage of this fact
398         * and allow things to proceed if we've specified the same
399         * number
400         */
401        addr = (struct cbcp_addr *)data->addr_start;
402        if (addr->type != CBCP_ADDR_PSTN) {
403          log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
404                     (int)addr->type);
405          return 0;
406        } else if (cbcp->fsm.type == CBCP_CLIENTNUM) {
407          /*
408           * If the peer's insisting on deciding the number, make sure
409           * it's one of the ones in our list.  If it is, let the peer
410           * think it's in control :-)
411           */
412          char list[sizeof cbcp->fsm.phone], *next;
413
414          strncpy(list, cbcp->fsm.phone, sizeof list - 1);
415          list[sizeof list - 1] = '\0';
416          for (next = strtok(list, ","); next; next = strtok(NULL, ","))
417            if (!strcmp(next, addr->addr)) {
418              cbcp->fsm.type = CBCP_SERVERNUM;
419              strcpy(cbcp->fsm.phone, next);
420              return 1;
421            }
422        }
423      }
424      log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n");
425      return 0;
426
427    case CBCP_LISTNUM:
428      if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) {
429        /*
430         * Search through ``data''s addresses and see if cbcp->fsm.phone
431         * contains any of them
432         */
433        char list[sizeof cbcp->fsm.phone], *next, *end;
434
435        addr = (struct cbcp_addr *)data->addr_start;
436        end = (char *)data + data->length;
437
438        while (addr->addr < end) {
439          if (addr->type == CBCP_ADDR_PSTN) {
440            strncpy(list, cbcp->fsm.phone, sizeof list - 1);
441            list[sizeof list - 1] = '\0';
442            for (next = strtok(list, ","); next; next = strtok(NULL, ","))
443              if (!strcmp(next, addr->addr)) {
444                cbcp->fsm.type = CBCP_LISTNUM;
445                strcpy(cbcp->fsm.phone, next);
446                return 1;
447              }
448          } else
449            log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n",
450                       (int)addr->type);
451          addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
452        }
453      }
454      log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n");
455      return 0;
456  }
457
458  log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type);
459  return 0;
460}
461
462static void
463cbcp_SendResponse(struct cbcp *cbcp)
464{
465  struct cbcp_data data;
466  struct cbcp_addr *addr;
467
468  /* Only callers send RESPONSEs */
469
470  log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name,
471             cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
472
473  data.type = cbcp->fsm.type;
474  data.delay = cbcp->fsm.delay;
475  addr = (struct cbcp_addr *)data.addr_start;
476  if (data.type == CBCP_NONUM)
477    data.length = (char *)&data.delay - (char *)&data;
478  else if (*cbcp->fsm.phone) {
479    addr->type = CBCP_ADDR_PSTN;
480    strcpy(addr->addr, cbcp->fsm.phone);
481    data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data;
482  } else
483    data.length = data.addr_start - (char *)&data;
484
485  cbcp_data_Show(&data);
486  cbcp_Output(cbcp, CBCP_RESPONSE, &data);
487  cbcp->fsm.restart--;
488  cbcp_StartTimer(cbcp, cbcp->fsm.delay);
489  cbcp_NewPhase(cbcp, CBCP_RESPSENT);	/* Wait for an ACK */
490}
491
492/* What to do after checking an incoming response */
493#define CBCP_ACTION_DOWN (0)
494#define CBCP_ACTION_REQ (1)
495#define CBCP_ACTION_ACK (2)
496
497static int
498cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
499{
500  /*
501   * We've received a RESPONSE (data).  Check if it agrees with
502   * our REQ (cbcp->fsm)
503   */
504  struct cbcp_addr *addr;
505
506  addr = (struct cbcp_addr *)data->addr_start;
507
508  if (data->type == cbcp->fsm.type) {
509    switch (cbcp->fsm.type) {
510      case CBCP_NONUM:
511        return CBCP_ACTION_ACK;
512
513      case CBCP_CLIENTNUM:
514        if ((char *)data + data->length <= addr->addr)
515          log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
516        else if (addr->type != CBCP_ADDR_PSTN)
517          log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
518                     addr->type);
519        else {
520          strcpy(cbcp->fsm.phone, addr->addr);
521          cbcp->fsm.delay = data->delay;
522          return CBCP_ACTION_ACK;
523        }
524        return CBCP_ACTION_DOWN;
525
526      case CBCP_SERVERNUM:
527        cbcp->fsm.delay = data->delay;
528        return CBCP_ACTION_ACK;
529
530      case CBCP_LISTNUM:
531        if ((char *)data + data->length <= addr->addr)
532          log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
533        else if (addr->type != CBCP_ADDR_PSTN)
534          log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
535                     addr->type);
536        else {
537          char list[sizeof cbcp->fsm.phone], *next;
538
539          strncpy(list, cbcp->fsm.phone, sizeof list - 1);
540          list[sizeof list - 1] = '\0';
541          for (next = strtok(list, ","); next; next = strtok(NULL, ","))
542            if (!strcmp(addr->addr, next)) {
543              strcpy(cbcp->fsm.phone, next);
544              cbcp->fsm.delay = data->delay;
545              return CBCP_ACTION_ACK;
546            }
547          log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
548                     "valid number !\n");
549        }
550        return CBCP_ACTION_DOWN;
551    }
552    log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n",
553               (int)cbcp->fsm.type);
554    return CBCP_ACTION_DOWN;
555  } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) {
556    /*
557     * Client doesn't want CBCP after all....
558     * We only allow this when ``set cbcp *'' has been specified.
559     */
560    cbcp->fsm.type = CBCP_NONUM;
561    return CBCP_ACTION_ACK;
562  }
563  log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
564  return CBCP_ACTION_REQ;
565}
566
567static void
568cbcp_SendAck(struct cbcp *cbcp)
569{
570  struct cbcp_data data;
571  struct cbcp_addr *addr;
572
573  /* Only callees send ACKs */
574
575  log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
576             cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
577
578  data.type = cbcp->fsm.type;
579  switch (data.type) {
580    case CBCP_NONUM:
581      data.length = (char *)&data.delay - (char *)&data;
582      break;
583    case CBCP_CLIENTNUM:
584      addr = (struct cbcp_addr *)data.addr_start;
585      addr->type = CBCP_ADDR_PSTN;
586      strcpy(addr->addr, cbcp->fsm.phone);
587      data.delay = cbcp->fsm.delay;
588      data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data;
589      break;
590    default:
591      data.delay = cbcp->fsm.delay;
592      data.length = data.addr_start - (char *)&data;
593      break;
594  }
595
596  cbcp_data_Show(&data);
597  cbcp_Output(cbcp, CBCP_ACK, &data);
598  cbcp->fsm.restart--;
599  cbcp_StartTimer(cbcp, cbcp->fsm.delay);
600  cbcp_NewPhase(cbcp, CBCP_ACKSENT);	/* Wait for an ACK */
601}
602
603void
604cbcp_Input(struct physical *p, struct mbuf *bp)
605{
606  struct cbcp_header *head;
607  struct cbcp_data *data;
608  struct cbcp *cbcp = &p->dl->cbcp;
609  int len;
610
611  len = mbuf_Length(bp);
612  if (len < sizeof(struct cbcp_header)) {
613    mbuf_Free(bp);
614    return;
615  }
616  head = (struct cbcp_header *)MBUF_CTOP(bp);
617  if (ntohs(head->length) != len) {
618    log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)"
619               " - ignored\n", head->code, ntohs(head->length), len);
620    mbuf_Free(bp);
621    return;
622  }
623
624  /* XXX check the id */
625
626  bp->offset += sizeof(struct cbcp_header);
627  bp->cnt -= sizeof(struct cbcp_header);
628  data = (struct cbcp_data *)MBUF_CTOP(bp);
629
630  switch (head->code) {
631    case CBCP_REQ:
632      log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n",
633                 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
634      cbcp_data_Show(data);
635      if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) {
636        timer_Stop(&cbcp->fsm.timer);
637        if (cbcp_AdjustResponse(cbcp, data)) {
638          cbcp->fsm.restart = DEF_REQs;
639          cbcp->fsm.id = head->id;
640          cbcp_SendResponse(cbcp);
641        } else
642          datalink_CBCPFailed(cbcp->p->dl);
643      } else
644        log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name);
645      break;
646
647    case CBCP_RESPONSE:
648      log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n",
649	         p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
650      cbcp_data_Show(data);
651      if (cbcp->fsm.id != head->id) {
652        log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
653                   cbcp->fsm.id, head->id);
654        cbcp->fsm.id = head->id;
655      }
656      if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) {
657        timer_Stop(&cbcp->fsm.timer);
658        switch (cbcp_CheckResponse(cbcp, data)) {
659          case CBCP_ACTION_REQ:
660            cbcp_SendReq(cbcp);
661            break;
662
663          case CBCP_ACTION_ACK:
664            cbcp->fsm.restart = DEF_REQs;
665            cbcp_SendAck(cbcp);
666            if (cbcp->fsm.type == CBCP_NONUM) {
667              /*
668               * Don't change state in case the peer doesn't get our ACK,
669               * just bring the layer up.
670               */
671              timer_Stop(&cbcp->fsm.timer);
672              datalink_NCPUp(cbcp->p->dl);
673            }
674            break;
675
676          default:
677            datalink_CBCPFailed(cbcp->p->dl);
678            break;
679        }
680      } else
681        log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
682      break;
683
684    case CBCP_ACK:
685      log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n",
686	         p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
687      cbcp_data_Show(data);
688      if (cbcp->fsm.id != head->id) {
689        log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
690                   cbcp->fsm.id, head->id);
691        cbcp->fsm.id = head->id;
692      }
693      if (cbcp->fsm.state == CBCP_RESPSENT) {
694        timer_Stop(&cbcp->fsm.timer);
695        datalink_CBCPComplete(cbcp->p->dl);
696        log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name);
697      } else
698        log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name);
699      break;
700
701    default:
702      log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n",
703               head->code, len);
704      break;
705  }
706
707  mbuf_Free(bp);
708}
709
710void
711cbcp_Down(struct cbcp *cbcp)
712{
713  timer_Stop(&cbcp->fsm.timer);
714  cbcp_NewPhase(cbcp, CBCP_CLOSED);
715  cbcp->required = 0;
716}
717
718void
719cbcp_ReceiveTerminateReq(struct physical *p)
720{
721  if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) {
722    /* Don't change our state in case the peer doesn't get the ACK */
723    p->dl->cbcp.required = 1;
724    log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name,
725               p->dl->cbcp.fsm.phone);
726  } else
727    cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED);
728}
729