Fictitious VM pages must remain structurally stable after free.
[dragonfly.git] / usr.sbin / ppp / cbcp.c
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: src/usr.sbin/ppp/cbcp.c,v 1.18.2.3 2002/09/01 02:12:22 brian Exp $
27  * $DragonFly: src/usr.sbin/ppp/cbcp.c,v 1.3 2004/02/03 07:11:47 dillon Exp $
28  */
29
30 #include <sys/param.h>
31
32 #ifdef __DragonFly__
33 #include <netinet/in.h>
34 #endif
35 #include <sys/un.h>
36
37 #include <string.h>
38 #include <termios.h>
39
40 #include "layer.h"
41 #include "defs.h"
42 #include "log.h"
43 #include "timer.h"
44 #include "descriptor.h"
45 #include "lqr.h"
46 #include "mbuf.h"
47 #include "fsm.h"
48 #include "throughput.h"
49 #include "hdlc.h"
50 #include "lcp.h"
51 #include "ccp.h"
52 #include "link.h"
53 #include "async.h"
54 #include "physical.h"
55 #include "proto.h"
56 #include "cbcp.h"
57 #include "mp.h"
58 #include "chat.h"
59 #include "auth.h"
60 #include "chap.h"
61 #include "datalink.h"
62
63 void
64 cbcp_Init(struct cbcp *cbcp, struct physical *p)
65 {
66   cbcp->required = 0;
67   cbcp->fsm.state = CBCP_CLOSED;
68   cbcp->fsm.id = 0;
69   cbcp->fsm.delay = 0;
70   *cbcp->fsm.phone = '\0';
71   memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer);
72   cbcp->p = p;
73 }
74
75 static void cbcp_SendReq(struct cbcp *);
76 static void cbcp_SendResponse(struct cbcp *);
77 static void cbcp_SendAck(struct cbcp *);
78
79 static void
80 cbcp_Timeout(void *v)
81 {
82   struct cbcp *cbcp = (struct cbcp *)v;
83
84   timer_Stop(&cbcp->fsm.timer);
85   if (cbcp->fsm.restart) {
86     switch (cbcp->fsm.state) {
87       case CBCP_CLOSED:
88       case CBCP_STOPPED:
89         log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
90                    cbcp->p->dl->name);
91         break;
92
93       case CBCP_REQSENT:
94         cbcp_SendReq(cbcp);
95         break;
96       case CBCP_RESPSENT:
97         cbcp_SendResponse(cbcp);
98         break;
99       case CBCP_ACKSENT:
100         cbcp_SendAck(cbcp);
101         break;
102     }
103   } else {
104     const char *missed;
105
106     switch (cbcp->fsm.state) {
107       case CBCP_STOPPED:
108         missed = "REQ";
109         break;
110       case CBCP_REQSENT:
111         missed = "RESPONSE";
112         break;
113       case CBCP_RESPSENT:
114         missed = "ACK";
115         break;
116       case CBCP_ACKSENT:
117         missed = "Terminate REQ";
118         break;
119       default:
120         log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
121                    cbcp->p->dl->name);
122         missed = NULL;
123         break;
124     }
125     if (missed)
126       log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n",
127                  cbcp->p->dl->name, missed);
128     datalink_CBCPFailed(cbcp->p->dl);
129   }
130 }
131
132 static void
133 cbcp_StartTimer(struct cbcp *cbcp, int timeout)
134 {
135   timer_Stop(&cbcp->fsm.timer);
136   cbcp->fsm.timer.func = cbcp_Timeout;
137   cbcp->fsm.timer.name = "cbcp";
138   cbcp->fsm.timer.load = timeout * SECTICKS;
139   cbcp->fsm.timer.arg = cbcp;
140   timer_Start(&cbcp->fsm.timer);
141 }
142
143 #define CBCP_CLOSED     (0)     /* Not in use */
144 #define CBCP_STOPPED    (1)     /* Waiting for a REQ */
145 #define CBCP_REQSENT    (2)     /* Waiting for a RESP */
146 #define CBCP_RESPSENT   (3)     /* Waiting for an ACK */
147 #define CBCP_ACKSENT    (4)     /* Waiting for an LCP Term REQ */
148
149 static const char * const cbcpname[] = {
150   "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
151 };
152
153 static const char *
154 cbcpstate(int s)
155 {
156   if (s < sizeof cbcpname / sizeof cbcpname[0])
157     return cbcpname[s];
158   return HexStr(s, NULL, 0);
159 }
160
161 static void
162 cbcp_NewPhase(struct cbcp *cbcp, int new)
163 {
164   if (cbcp->fsm.state != new) {
165     log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name,
166                cbcpstate(cbcp->fsm.state), cbcpstate(new));
167     cbcp->fsm.state = new;
168   }
169 }
170
171 struct cbcp_header {
172   u_char code;
173   u_char id;
174   u_int16_t length;     /* Network byte order */
175 };
176
177
178 /* cbcp_header::code values */
179 #define CBCP_REQ        (1)
180 #define CBCP_RESPONSE   (2)
181 #define CBCP_ACK        (3)
182
183 struct cbcp_data {
184   u_char type;
185   u_char length;
186   u_char delay;
187   char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */
188 };
189
190 /* cbcp_data::type values */
191 #define CBCP_NONUM      (1)
192 #define CBCP_CLIENTNUM  (2)
193 #define CBCP_SERVERNUM  (3)
194 #define CBCP_LISTNUM    (4)
195
196 static void
197 cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data)
198 {
199   struct cbcp_header *head;
200   struct mbuf *bp;
201
202   bp = m_get(sizeof *head + data->length, MB_CBCPOUT);
203   head = (struct cbcp_header *)MBUF_CTOP(bp);
204   head->code = code;
205   head->id = cbcp->fsm.id;
206   head->length = htons(sizeof *head + data->length);
207   memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length);
208   log_DumpBp(LogDEBUG, "cbcp_Output", bp);
209   link_PushPacket(&cbcp->p->link, bp, cbcp->p->dl->bundle,
210                   LINK_QUEUES(&cbcp->p->link) - 1, PROTO_CBCP);
211 }
212
213 static const char *
214 cbcp_data_Type(int type)
215 {
216   static const char * const types[] = {
217     "No callback", "User-spec", "Server-spec", "list"
218   };
219
220   if (type < 1 || type > sizeof types / sizeof types[0])
221     return HexStr(type, NULL, 0);
222   return types[type-1];
223 }
224
225 struct cbcp_addr {
226   u_char type;
227   char addr[1];         /* Really ASCIIZ */
228 };
229
230 /* cbcp_data::type values */
231 #define CBCP_ADDR_PSTN  (1)
232
233 static void
234 cbcp_data_Show(struct cbcp_data *data)
235 {
236   struct cbcp_addr *addr;
237   char *end;
238
239   addr = (struct cbcp_addr *)data->addr_start;
240   end = (char *)data + data->length;
241   *end = '\0';
242
243   log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type));
244   if ((char *)&data->delay < end) {
245     log_Printf(LogCBCP, " DELAY %d\n", data->delay);
246     while (addr->addr < end) {
247       if (addr->type == CBCP_ADDR_PSTN)
248         log_Printf(LogCBCP, " ADDR %s\n", addr->addr);
249       else
250         log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type);
251       addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
252     }
253   }
254 }
255
256 static void
257 cbcp_SendReq(struct cbcp *cbcp)
258 {
259   struct cbcp_data data;
260   struct cbcp_addr *addr;
261   char list[sizeof cbcp->fsm.phone], *next;
262   int len, max;
263
264   /* Only callees send REQs */
265
266   log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name,
267              cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
268   data.type = cbcp->fsm.type;
269   data.delay = 0;
270   strncpy(list, cbcp->fsm.phone, sizeof list - 1);
271   list[sizeof list - 1] = '\0';
272
273   switch (data.type) {
274     case CBCP_CLIENTNUM:
275       addr = (struct cbcp_addr *)data.addr_start;
276       addr->type = CBCP_ADDR_PSTN;
277       *addr->addr = '\0';
278       data.length = addr->addr - (char *)&data;
279       break;
280
281     case CBCP_LISTNUM:
282       addr = (struct cbcp_addr *)data.addr_start;
283       for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
284         len = strlen(next);
285         max = data.addr_start + sizeof data.addr_start - addr->addr - 1;
286         if (len <= max) {
287           addr->type = CBCP_ADDR_PSTN;
288           strcpy(addr->addr, next);
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
313 void
314 cbcp_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
352 static int
353 cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data)
354 {
355   /*
356    * We've received a REQ (data).  Adjust our reponse (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
477 static void
478 cbcp_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     strcpy(addr->addr, cbcp->fsm.phone);
496     data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data;
497   } else
498     data.length = data.addr_start - (char *)&data;
499
500   cbcp_data_Show(&data);
501   cbcp_Output(cbcp, CBCP_RESPONSE, &data);
502   cbcp->fsm.restart--;
503   cbcp_StartTimer(cbcp, cbcp->fsm.delay);
504   cbcp_NewPhase(cbcp, CBCP_RESPSENT);   /* Wait for an ACK */
505 }
506
507 /* What to do after checking an incoming response */
508 #define CBCP_ACTION_DOWN (0)
509 #define CBCP_ACTION_REQ (1)
510 #define CBCP_ACTION_ACK (2)
511
512 static int
513 cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
514 {
515   /*
516    * We've received a RESPONSE (data).  Check if it agrees with
517    * our REQ (cbcp->fsm)
518    */
519   struct cbcp_addr *addr;
520
521   addr = (struct cbcp_addr *)data->addr_start;
522
523   if (data->type == cbcp->fsm.type) {
524     switch (cbcp->fsm.type) {
525       case CBCP_NONUM:
526         return CBCP_ACTION_ACK;
527
528       case CBCP_CLIENTNUM:
529         if ((char *)data + data->length <= addr->addr)
530           log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
531         else if (addr->type != CBCP_ADDR_PSTN)
532           log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
533                      addr->type);
534         else {
535           strcpy(cbcp->fsm.phone, addr->addr);
536           cbcp->fsm.delay = data->delay;
537           return CBCP_ACTION_ACK;
538         }
539         return CBCP_ACTION_DOWN;
540
541       case CBCP_SERVERNUM:
542         cbcp->fsm.delay = data->delay;
543         return CBCP_ACTION_ACK;
544
545       case CBCP_LISTNUM:
546         if ((char *)data + data->length <= addr->addr)
547           log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
548         else if (addr->type != CBCP_ADDR_PSTN)
549           log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
550                      addr->type);
551         else {
552           char list[sizeof cbcp->fsm.phone], *next;
553
554           strncpy(list, cbcp->fsm.phone, sizeof list - 1);
555           list[sizeof list - 1] = '\0';
556           for (next = strtok(list, ","); next; next = strtok(NULL, ","))
557             if (!strcmp(addr->addr, next)) {
558               strcpy(cbcp->fsm.phone, next);
559               cbcp->fsm.delay = data->delay;
560               return CBCP_ACTION_ACK;
561             }
562           log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
563                      "valid number !\n");
564         }
565         return CBCP_ACTION_DOWN;
566     }
567     log_Printf(LogPHASE, "Internal CBCP error - agreed on %d !\n",
568                (int)cbcp->fsm.type);
569     return CBCP_ACTION_DOWN;
570   } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) {
571     /*
572      * Client doesn't want CBCP after all....
573      * We only allow this when ``set cbcp *'' has been specified.
574      */
575     cbcp->fsm.type = CBCP_NONUM;
576     return CBCP_ACTION_ACK;
577   }
578   log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
579   return CBCP_ACTION_REQ;
580 }
581
582 static void
583 cbcp_SendAck(struct cbcp *cbcp)
584 {
585   struct cbcp_data data;
586   struct cbcp_addr *addr;
587
588   /* Only callees send ACKs */
589
590   log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
591              cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
592
593   data.type = cbcp->fsm.type;
594   switch (data.type) {
595     case CBCP_NONUM:
596       data.length = (char *)&data.delay - (char *)&data;
597       break;
598     case CBCP_CLIENTNUM:
599       addr = (struct cbcp_addr *)data.addr_start;
600       addr->type = CBCP_ADDR_PSTN;
601       strcpy(addr->addr, cbcp->fsm.phone);
602       data.delay = cbcp->fsm.delay;
603       data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data;
604       break;
605     default:
606       data.delay = cbcp->fsm.delay;
607       data.length = data.addr_start - (char *)&data;
608       break;
609   }
610
611   cbcp_data_Show(&data);
612   cbcp_Output(cbcp, CBCP_ACK, &data);
613   cbcp->fsm.restart--;
614   cbcp_StartTimer(cbcp, cbcp->fsm.delay);
615   cbcp_NewPhase(cbcp, CBCP_ACKSENT);    /* Wait for an ACK */
616 }
617
618 extern struct mbuf *
619 cbcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
620 {
621   struct physical *p = link2physical(l);
622   struct cbcp_header *head;
623   struct cbcp_data *data;
624   struct cbcp *cbcp = &p->dl->cbcp;
625   int len;
626
627   if (p == NULL) {
628     log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n");
629     m_freem(bp);
630     return NULL;
631   }
632
633   bp = m_pullup(bp);
634   len = m_length(bp);
635   if (len < sizeof(struct cbcp_header)) {
636     m_freem(bp);
637     return NULL;
638   }
639   head = (struct cbcp_header *)MBUF_CTOP(bp);
640   if (ntohs(head->length) != len) {
641     log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)"
642                " - ignored\n", head->code, ntohs(head->length), len);
643     m_freem(bp);
644     return NULL;
645   }
646   m_settype(bp, MB_CBCPIN);
647
648   /* XXX check the id */
649
650   bp->m_offset += sizeof(struct cbcp_header);
651   bp->m_len -= sizeof(struct cbcp_header);
652   data = (struct cbcp_data *)MBUF_CTOP(bp);
653
654   switch (head->code) {
655     case CBCP_REQ:
656       log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n",
657                  p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
658       cbcp_data_Show(data);
659       if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) {
660         timer_Stop(&cbcp->fsm.timer);
661         if (cbcp_AdjustResponse(cbcp, data)) {
662           cbcp->fsm.restart = DEF_FSMTRIES;
663           cbcp->fsm.id = head->id;
664           cbcp_SendResponse(cbcp);
665         } else
666           datalink_CBCPFailed(cbcp->p->dl);
667       } else
668         log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name);
669       break;
670
671     case CBCP_RESPONSE:
672       log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n",
673                  p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
674       cbcp_data_Show(data);
675       if (cbcp->fsm.id != head->id) {
676         log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
677                    cbcp->fsm.id, head->id);
678         cbcp->fsm.id = head->id;
679       }
680       if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) {
681         timer_Stop(&cbcp->fsm.timer);
682         switch (cbcp_CheckResponse(cbcp, data)) {
683           case CBCP_ACTION_REQ:
684             cbcp_SendReq(cbcp);
685             break;
686
687           case CBCP_ACTION_ACK:
688             cbcp->fsm.restart = DEF_FSMTRIES;
689             cbcp_SendAck(cbcp);
690             if (cbcp->fsm.type == CBCP_NONUM) {
691               /*
692                * Don't change state in case the peer doesn't get our ACK,
693                * just bring the layer up.
694                */
695               timer_Stop(&cbcp->fsm.timer);
696               datalink_NCPUp(cbcp->p->dl);
697             }
698             break;
699
700           default:
701             datalink_CBCPFailed(cbcp->p->dl);
702             break;
703         }
704       } else
705         log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
706       break;
707
708     case CBCP_ACK:
709       log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n",
710                  p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
711       cbcp_data_Show(data);
712       if (cbcp->fsm.id != head->id) {
713         log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
714                    cbcp->fsm.id, head->id);
715         cbcp->fsm.id = head->id;
716       }
717       if (cbcp->fsm.type == CBCP_NONUM) {
718         /*
719          * Don't change state in case the peer doesn't get our ACK,
720          * just bring the layer up.
721          */
722         timer_Stop(&cbcp->fsm.timer);
723         datalink_NCPUp(cbcp->p->dl);
724       } else if (cbcp->fsm.state == CBCP_RESPSENT) {
725         timer_Stop(&cbcp->fsm.timer);
726         datalink_CBCPComplete(cbcp->p->dl);
727         log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name);
728       } else
729         log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name);
730       break;
731
732     default:
733       log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n",
734                head->code, len);
735       break;
736   }
737
738   m_freem(bp);
739   return NULL;
740 }
741
742 void
743 cbcp_Down(struct cbcp *cbcp)
744 {
745   timer_Stop(&cbcp->fsm.timer);
746   cbcp_NewPhase(cbcp, CBCP_CLOSED);
747   cbcp->required = 0;
748 }
749
750 void
751 cbcp_ReceiveTerminateReq(struct physical *p)
752 {
753   if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) {
754     /* Don't change our state in case the peer doesn't get the ACK */
755     p->dl->cbcp.required = 1;
756     log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name,
757                p->dl->cbcp.fsm.phone);
758   } else
759     cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED);
760 }