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