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