xref: /freebsd/usr.sbin/ppp/cbcp.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
1 /*-
2  * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$Id: cbcp.c,v 1.12 1999/05/08 11:06:10 brian Exp $
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 "lcp.h"
45 #include "throughput.h"
46 #include "hdlc.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 *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 "???";
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 = mbuf_Alloc(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                   PRI_LINK, PROTO_CBCP);
207 }
208 
209 static const char *
210 cbcp_data_Type(int type)
211 {
212   static const char *types[] = {
213     "No callback", "User-spec", "Server-spec", "list"
214   };
215 
216   if (type < 1 || type > sizeof types / sizeof types[0])
217     return "???";
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       /*
360        * If the callee offers no callback, we send our desired response
361        * anyway.  This is what Win95 does - although I can't find this
362        * behaviour documented in the spec....
363        */
364       return 1;
365 
366     case CBCP_CLIENTNUM:
367       if (cbcp->fsm.type == CBCP_CLIENTNUM) {
368         char *ptr;
369 
370         if (data->length > data->addr_start - (char *)data) {
371           /*
372            * The peer has given us an address type spec - make sure we
373            * understand !
374            */
375           addr = (struct cbcp_addr *)data->addr_start;
376           if (addr->type != CBCP_ADDR_PSTN) {
377             log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
378                        (int)addr->type);
379             return 0;
380           }
381         }
382         /* we accept the REQ even if the peer didn't specify an addr->type */
383         ptr = strchr(cbcp->fsm.phone, ',');
384         if (ptr)
385           *ptr = '\0';		/* Just use the first number in our list */
386         return 1;
387       }
388       log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n");
389       return 0;
390 
391     case CBCP_SERVERNUM:
392       if (cbcp->fsm.type == CBCP_SERVERNUM) {
393         *cbcp->fsm.phone = '\0';
394         return 1;
395       }
396       if (data->length > data->addr_start - (char *)data) {
397         /*
398          * This violates the spec, but if the peer has told us the
399          * number it wants to call back, take advantage of this fact
400          * and allow things to proceed if we've specified the same
401          * number
402          */
403         addr = (struct cbcp_addr *)data->addr_start;
404         if (addr->type != CBCP_ADDR_PSTN) {
405           log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
406                      (int)addr->type);
407           return 0;
408         } else if (cbcp->fsm.type == CBCP_CLIENTNUM) {
409           /*
410            * If the peer's insisting on deciding the number, make sure
411            * it's one of the ones in our list.  If it is, let the peer
412            * think it's in control :-)
413            */
414           char list[sizeof cbcp->fsm.phone], *next;
415 
416           strncpy(list, cbcp->fsm.phone, sizeof list - 1);
417           list[sizeof list - 1] = '\0';
418           for (next = strtok(list, ","); next; next = strtok(NULL, ","))
419             if (!strcmp(next, addr->addr)) {
420               cbcp->fsm.type = CBCP_SERVERNUM;
421               strcpy(cbcp->fsm.phone, next);
422               return 1;
423             }
424         }
425       }
426       log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n");
427       return 0;
428 
429     case CBCP_LISTNUM:
430       if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) {
431         /*
432          * Search through ``data''s addresses and see if cbcp->fsm.phone
433          * contains any of them
434          */
435         char list[sizeof cbcp->fsm.phone], *next, *end;
436 
437         addr = (struct cbcp_addr *)data->addr_start;
438         end = (char *)data + data->length;
439 
440         while (addr->addr < end) {
441           if (addr->type == CBCP_ADDR_PSTN) {
442             strncpy(list, cbcp->fsm.phone, sizeof list - 1);
443             list[sizeof list - 1] = '\0';
444             for (next = strtok(list, ","); next; next = strtok(NULL, ","))
445               if (!strcmp(next, addr->addr)) {
446                 cbcp->fsm.type = CBCP_LISTNUM;
447                 strcpy(cbcp->fsm.phone, next);
448                 return 1;
449               }
450           } else
451             log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n",
452                        (int)addr->type);
453           addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
454         }
455       }
456       log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n");
457       return 0;
458   }
459 
460   log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type);
461   return 0;
462 }
463 
464 static void
465 cbcp_SendResponse(struct cbcp *cbcp)
466 {
467   struct cbcp_data data;
468   struct cbcp_addr *addr;
469 
470   /* Only callers send RESPONSEs */
471 
472   log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name,
473              cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
474 
475   data.type = cbcp->fsm.type;
476   data.delay = cbcp->fsm.delay;
477   addr = (struct cbcp_addr *)data.addr_start;
478   if (data.type == CBCP_NONUM)
479     data.length = (char *)&data.delay - (char *)&data;
480   else if (*cbcp->fsm.phone) {
481     addr->type = CBCP_ADDR_PSTN;
482     strcpy(addr->addr, cbcp->fsm.phone);
483     data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data;
484   } else
485     data.length = data.addr_start - (char *)&data;
486 
487   cbcp_data_Show(&data);
488   cbcp_Output(cbcp, CBCP_RESPONSE, &data);
489   cbcp->fsm.restart--;
490   cbcp_StartTimer(cbcp, cbcp->fsm.delay);
491   cbcp_NewPhase(cbcp, CBCP_RESPSENT);	/* Wait for an ACK */
492 }
493 
494 /* What to do after checking an incoming response */
495 #define CBCP_ACTION_DOWN (0)
496 #define CBCP_ACTION_REQ (1)
497 #define CBCP_ACTION_ACK (2)
498 
499 static int
500 cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
501 {
502   /*
503    * We've received a RESPONSE (data).  Check if it agrees with
504    * our REQ (cbcp->fsm)
505    */
506   struct cbcp_addr *addr;
507 
508   addr = (struct cbcp_addr *)data->addr_start;
509 
510   if (data->type == cbcp->fsm.type) {
511     switch (cbcp->fsm.type) {
512       case CBCP_NONUM:
513         return CBCP_ACTION_ACK;
514 
515       case CBCP_CLIENTNUM:
516         if ((char *)data + data->length <= addr->addr)
517           log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
518         else if (addr->type != CBCP_ADDR_PSTN)
519           log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
520                      addr->type);
521         else {
522           strcpy(cbcp->fsm.phone, addr->addr);
523           cbcp->fsm.delay = data->delay;
524           return CBCP_ACTION_ACK;
525         }
526         return CBCP_ACTION_DOWN;
527 
528       case CBCP_SERVERNUM:
529         cbcp->fsm.delay = data->delay;
530         return CBCP_ACTION_ACK;
531 
532       case CBCP_LISTNUM:
533         if ((char *)data + data->length <= addr->addr)
534           log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
535         else if (addr->type != CBCP_ADDR_PSTN)
536           log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
537                      addr->type);
538         else {
539           char list[sizeof cbcp->fsm.phone], *next;
540 
541           strncpy(list, cbcp->fsm.phone, sizeof list - 1);
542           list[sizeof list - 1] = '\0';
543           for (next = strtok(list, ","); next; next = strtok(NULL, ","))
544             if (!strcmp(addr->addr, next)) {
545               strcpy(cbcp->fsm.phone, next);
546               cbcp->fsm.delay = data->delay;
547               return CBCP_ACTION_ACK;
548             }
549           log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
550                      "valid number !\n");
551         }
552         return CBCP_ACTION_DOWN;
553     }
554     log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n",
555                (int)cbcp->fsm.type);
556     return CBCP_ACTION_DOWN;
557   } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) {
558     /*
559      * Client doesn't want CBCP after all....
560      * We only allow this when ``set cbcp *'' has been specified.
561      */
562     cbcp->fsm.type = CBCP_NONUM;
563     return CBCP_ACTION_ACK;
564   }
565   log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
566   return CBCP_ACTION_REQ;
567 }
568 
569 static void
570 cbcp_SendAck(struct cbcp *cbcp)
571 {
572   struct cbcp_data data;
573   struct cbcp_addr *addr;
574 
575   /* Only callees send ACKs */
576 
577   log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
578              cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
579 
580   data.type = cbcp->fsm.type;
581   switch (data.type) {
582     case CBCP_NONUM:
583       data.length = (char *)&data.delay - (char *)&data;
584       break;
585     case CBCP_CLIENTNUM:
586       addr = (struct cbcp_addr *)data.addr_start;
587       addr->type = CBCP_ADDR_PSTN;
588       strcpy(addr->addr, cbcp->fsm.phone);
589       data.delay = cbcp->fsm.delay;
590       data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data;
591       break;
592     default:
593       data.delay = cbcp->fsm.delay;
594       data.length = data.addr_start - (char *)&data;
595       break;
596   }
597 
598   cbcp_data_Show(&data);
599   cbcp_Output(cbcp, CBCP_ACK, &data);
600   cbcp->fsm.restart--;
601   cbcp_StartTimer(cbcp, cbcp->fsm.delay);
602   cbcp_NewPhase(cbcp, CBCP_ACKSENT);	/* Wait for an ACK */
603 }
604 
605 extern struct mbuf *
606 cbcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
607 {
608   struct physical *p = link2physical(l);
609   struct cbcp_header *head;
610   struct cbcp_data *data;
611   struct cbcp *cbcp = &p->dl->cbcp;
612   int len;
613 
614   if (p == NULL) {
615     log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n");
616     mbuf_Free(bp);
617     return NULL;
618   }
619 
620   bp = mbuf_Contiguous(bp);
621   len = mbuf_Length(bp);
622   if (len < sizeof(struct cbcp_header)) {
623     mbuf_Free(bp);
624     return NULL;
625   }
626   head = (struct cbcp_header *)MBUF_CTOP(bp);
627   if (ntohs(head->length) != len) {
628     log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)"
629                " - ignored\n", head->code, ntohs(head->length), len);
630     mbuf_Free(bp);
631     return NULL;
632   }
633   mbuf_SetType(bp, MB_CBCPIN);
634 
635   /* XXX check the id */
636 
637   bp->offset += sizeof(struct cbcp_header);
638   bp->cnt -= sizeof(struct cbcp_header);
639   data = (struct cbcp_data *)MBUF_CTOP(bp);
640 
641   switch (head->code) {
642     case CBCP_REQ:
643       log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n",
644                  p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
645       cbcp_data_Show(data);
646       if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) {
647         timer_Stop(&cbcp->fsm.timer);
648         if (cbcp_AdjustResponse(cbcp, data)) {
649           cbcp->fsm.restart = DEF_FSMTRIES;
650           cbcp->fsm.id = head->id;
651           cbcp_SendResponse(cbcp);
652         } else
653           datalink_CBCPFailed(cbcp->p->dl);
654       } else
655         log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name);
656       break;
657 
658     case CBCP_RESPONSE:
659       log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n",
660 	         p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
661       cbcp_data_Show(data);
662       if (cbcp->fsm.id != head->id) {
663         log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
664                    cbcp->fsm.id, head->id);
665         cbcp->fsm.id = head->id;
666       }
667       if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) {
668         timer_Stop(&cbcp->fsm.timer);
669         switch (cbcp_CheckResponse(cbcp, data)) {
670           case CBCP_ACTION_REQ:
671             cbcp_SendReq(cbcp);
672             break;
673 
674           case CBCP_ACTION_ACK:
675             cbcp->fsm.restart = DEF_FSMTRIES;
676             cbcp_SendAck(cbcp);
677             if (cbcp->fsm.type == CBCP_NONUM) {
678               /*
679                * Don't change state in case the peer doesn't get our ACK,
680                * just bring the layer up.
681                */
682               timer_Stop(&cbcp->fsm.timer);
683               datalink_NCPUp(cbcp->p->dl);
684             }
685             break;
686 
687           default:
688             datalink_CBCPFailed(cbcp->p->dl);
689             break;
690         }
691       } else
692         log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
693       break;
694 
695     case CBCP_ACK:
696       log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n",
697 	         p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
698       cbcp_data_Show(data);
699       if (cbcp->fsm.id != head->id) {
700         log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
701                    cbcp->fsm.id, head->id);
702         cbcp->fsm.id = head->id;
703       }
704       if (cbcp->fsm.state == CBCP_RESPSENT) {
705         timer_Stop(&cbcp->fsm.timer);
706         datalink_CBCPComplete(cbcp->p->dl);
707         log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name);
708       } else
709         log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name);
710       break;
711 
712     default:
713       log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n",
714                head->code, len);
715       break;
716   }
717 
718   mbuf_Free(bp);
719   return NULL;
720 }
721 
722 void
723 cbcp_Down(struct cbcp *cbcp)
724 {
725   timer_Stop(&cbcp->fsm.timer);
726   cbcp_NewPhase(cbcp, CBCP_CLOSED);
727   cbcp->required = 0;
728 }
729 
730 void
731 cbcp_ReceiveTerminateReq(struct physical *p)
732 {
733   if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) {
734     /* Don't change our state in case the peer doesn't get the ACK */
735     p->dl->cbcp.required = 1;
736     log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name,
737                p->dl->cbcp.fsm.phone);
738   } else
739     cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED);
740 }
741