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