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