xref: /freebsd/usr.sbin/ppp/cbcp.c (revision ab40f58ccfe6c07ebefddc72f4661a52fe746353)
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$
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 
64 void
65 cbcp_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 
76 static void cbcp_SendReq(struct cbcp *);
77 static void cbcp_SendResponse(struct cbcp *);
78 static void cbcp_SendAck(struct cbcp *);
79 
80 static void
81 cbcp_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 
133 static void
134 cbcp_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 
150 static const char * const cbcpname[] = {
151   "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
152 };
153 
154 static const char *
155 cbcpstate(unsigned s)
156 {
157   if (s < sizeof cbcpname / sizeof cbcpname[0])
158     return cbcpname[s];
159   return HexStr(s, NULL, 0);
160 }
161 
162 static void
163 cbcp_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 
172 struct 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 
184 struct 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 
197 static void
198 cbcp_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 
214 static const char *
215 cbcp_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 
226 struct 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 
234 static void
235 cbcp_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 
257 static void
258 cbcp_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 
315 void
316 cbcp_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 
354 static int
355 cbcp_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 
479 static void
480 cbcp_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 
515 static int
516 cbcp_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 
586 static void
587 cbcp_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 
623 extern struct mbuf *
624 cbcp_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 
747 void
748 cbcp_Down(struct cbcp *cbcp)
749 {
750   timer_Stop(&cbcp->fsm.timer);
751   cbcp_NewPhase(cbcp, CBCP_CLOSED);
752   cbcp->required = 0;
753 }
754 
755 void
756 cbcp_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