bsd-family-tree: Small sync with FreeBSD.
[dragonfly.git] / usr.sbin / ppp / cbcp.c
blob575cd8be7318e689c79d71dd0b0eefc8cefb51b7
1 /*-
2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3 * All rights reserved.
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.
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.
26 * $FreeBSD: src/usr.sbin/ppp/cbcp.c,v 1.18.2.3 2002/09/01 02:12:22 brian Exp $
29 #include <sys/param.h>
31 #ifdef __DragonFly__
32 #include <netinet/in.h>
33 #endif
34 #include <sys/un.h>
36 #include <string.h>
37 #include <termios.h>
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"
62 void
63 cbcp_Init(struct cbcp *cbcp, struct physical *p)
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;
74 static void cbcp_SendReq(struct cbcp *);
75 static void cbcp_SendResponse(struct cbcp *);
76 static void cbcp_SendAck(struct cbcp *);
78 static void
79 cbcp_Timeout(void *v)
81 struct cbcp *cbcp = (struct cbcp *)v;
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;
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;
102 } else {
103 const char *missed;
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;
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);
131 static void
132 cbcp_StartTimer(struct cbcp *cbcp, int timeout)
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);
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 */
148 static const char * const cbcpname[] = {
149 "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
152 static const char *
153 cbcpstate(unsigned s)
155 if (s < NELEM(cbcpname))
156 return cbcpname[s];
157 return HexStr(s, NULL, 0);
160 static void
161 cbcp_NewPhase(struct cbcp *cbcp, int new)
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;
170 struct cbcp_header {
171 u_char code;
172 u_char id;
173 u_int16_t length; /* Network byte order */
177 /* cbcp_header::code values */
178 #define CBCP_REQ (1)
179 #define CBCP_RESPONSE (2)
180 #define CBCP_ACK (3)
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 */
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)
195 static void
196 cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data)
198 struct cbcp_header *head;
199 struct mbuf *bp;
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);
212 static const char *
213 cbcp_data_Type(unsigned type)
215 static const char * const types[] = {
216 "No callback", "User-spec", "Server-spec", "list"
219 if (type < 1 || type > NELEM(types))
220 return HexStr(type, NULL, 0);
221 return types[type-1];
224 struct cbcp_addr {
225 u_char type;
226 char addr[1]; /* Really ASCIIZ */
229 /* cbcp_data::type values */
230 #define CBCP_ADDR_PSTN (1)
232 static void
233 cbcp_data_Show(struct cbcp_data *data)
235 struct cbcp_addr *addr;
236 char *end;
238 addr = (struct cbcp_addr *)data->addr_start;
239 end = (char *)data + data->length;
240 *end = '\0';
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);
255 static void
256 cbcp_SendReq(struct cbcp *cbcp)
258 struct cbcp_data data;
259 struct cbcp_addr *addr;
260 char list[sizeof cbcp->fsm.phone], *next;
261 int len, max;
263 /* Only callees send REQs */
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';
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;
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 strcpy(addr->addr, next);
288 addr = (struct cbcp_addr *)((char *)addr + len + 2);
289 } else
290 log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n",
291 next);
293 data.length = (char *)addr - (char *)&data;
294 break;
296 case CBCP_SERVERNUM:
297 data.length = data.addr_start - (char *)&data;
298 break;
300 default:
301 data.length = (char *)&data.delay - (char *)&data;
302 break;
305 cbcp_data_Show(&data);
306 cbcp_Output(cbcp, CBCP_REQ, &data);
307 cbcp->fsm.restart--;
308 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
309 cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */
312 void
313 cbcp_Up(struct cbcp *cbcp)
315 struct lcp *lcp = &cbcp->p->link.lcp;
317 cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay;
318 if (*cbcp->p->dl->peer.authname == '\0' ||
319 !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone,
320 sizeof cbcp->fsm.phone)) {
321 strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone,
322 sizeof cbcp->fsm.phone - 1);
323 cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0';
326 if (lcp->want_callback.opmask) {
327 if (*cbcp->fsm.phone == '\0')
328 cbcp->fsm.type = CBCP_NONUM;
329 else if (!strcmp(cbcp->fsm.phone, "*")) {
330 cbcp->fsm.type = CBCP_SERVERNUM;
331 *cbcp->fsm.phone = '\0';
332 } else
333 cbcp->fsm.type = CBCP_CLIENTNUM;
334 cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */
335 cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_FSMTRIES);
336 } else {
337 if (*cbcp->fsm.phone == '\0')
338 cbcp->fsm.type = CBCP_NONUM;
339 else if (!strcmp(cbcp->fsm.phone, "*")) {
340 cbcp->fsm.type = CBCP_CLIENTNUM;
341 *cbcp->fsm.phone = '\0';
342 } else if (strchr(cbcp->fsm.phone, ','))
343 cbcp->fsm.type = CBCP_LISTNUM;
344 else
345 cbcp->fsm.type = CBCP_SERVERNUM;
346 cbcp->fsm.restart = DEF_FSMTRIES;
347 cbcp_SendReq(cbcp);
351 static int
352 cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data)
355 * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*)
356 * so that we (hopefully) agree with the peer
358 struct cbcp_addr *addr;
360 switch (data->type) {
361 case CBCP_NONUM:
362 if (cbcp->p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))
364 * if ``none'' is a configured callback possibility
365 * (ie, ``set callback cbcp none''), go along with the callees
366 * request
368 cbcp->fsm.type = CBCP_NONUM;
371 * Otherwise, we send our desired response anyway. This seems to be
372 * what Win95 does - although I can't find this behaviour documented
373 * in the CBCP spec....
376 return 1;
378 case CBCP_CLIENTNUM:
379 if (cbcp->fsm.type == CBCP_CLIENTNUM) {
380 char *ptr;
382 if (data->length > data->addr_start - (char *)data) {
384 * The peer has given us an address type spec - make sure we
385 * understand !
387 addr = (struct cbcp_addr *)data->addr_start;
388 if (addr->type != CBCP_ADDR_PSTN) {
389 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
390 (int)addr->type);
391 return 0;
394 /* we accept the REQ even if the peer didn't specify an addr->type */
395 ptr = strchr(cbcp->fsm.phone, ',');
396 if (ptr)
397 *ptr = '\0'; /* Just use the first number in our list */
398 return 1;
400 log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n");
401 return 0;
403 case CBCP_SERVERNUM:
404 if (cbcp->fsm.type == CBCP_SERVERNUM) {
405 *cbcp->fsm.phone = '\0';
406 return 1;
408 if (data->length > data->addr_start - (char *)data) {
410 * This violates the spec, but if the peer has told us the
411 * number it wants to call back, take advantage of this fact
412 * and allow things to proceed if we've specified the same
413 * number
415 addr = (struct cbcp_addr *)data->addr_start;
416 if (addr->type != CBCP_ADDR_PSTN) {
417 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
418 (int)addr->type);
419 return 0;
420 } else if (cbcp->fsm.type == CBCP_CLIENTNUM) {
422 * If the peer's insisting on deciding the number, make sure
423 * it's one of the ones in our list. If it is, let the peer
424 * think it's in control :-)
426 char list[sizeof cbcp->fsm.phone], *next;
428 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
429 list[sizeof list - 1] = '\0';
430 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
431 if (!strcmp(next, addr->addr)) {
432 cbcp->fsm.type = CBCP_SERVERNUM;
433 strcpy(cbcp->fsm.phone, next);
434 return 1;
438 log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n");
439 return 0;
441 case CBCP_LISTNUM:
442 if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) {
444 * Search through ``data''s addresses and see if cbcp->fsm.phone
445 * contains any of them
447 char list[sizeof cbcp->fsm.phone], *next, *end;
449 addr = (struct cbcp_addr *)data->addr_start;
450 end = (char *)data + data->length;
452 while (addr->addr < end) {
453 if (addr->type == CBCP_ADDR_PSTN) {
454 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
455 list[sizeof list - 1] = '\0';
456 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
457 if (!strcmp(next, addr->addr)) {
458 cbcp->fsm.type = CBCP_LISTNUM;
459 strcpy(cbcp->fsm.phone, next);
460 return 1;
462 } else
463 log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n",
464 (int)addr->type);
465 addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
468 log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n");
469 return 0;
472 log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type);
473 return 0;
476 static void
477 cbcp_SendResponse(struct cbcp *cbcp)
479 struct cbcp_data data;
480 struct cbcp_addr *addr;
482 /* Only callers send RESPONSEs */
484 log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name,
485 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
487 data.type = cbcp->fsm.type;
488 data.delay = cbcp->fsm.delay;
489 addr = (struct cbcp_addr *)data.addr_start;
490 if (data.type == CBCP_NONUM)
491 data.length = (char *)&data.delay - (char *)&data;
492 else if (*cbcp->fsm.phone) {
493 addr->type = CBCP_ADDR_PSTN;
494 strcpy(addr->addr, cbcp->fsm.phone);
495 data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data;
496 } else
497 data.length = data.addr_start - (char *)&data;
499 cbcp_data_Show(&data);
500 cbcp_Output(cbcp, CBCP_RESPONSE, &data);
501 cbcp->fsm.restart--;
502 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
503 cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */
506 /* What to do after checking an incoming response */
507 #define CBCP_ACTION_DOWN (0)
508 #define CBCP_ACTION_REQ (1)
509 #define CBCP_ACTION_ACK (2)
511 static int
512 cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
515 * We've received a RESPONSE (data). Check if it agrees with
516 * our REQ (cbcp->fsm)
518 struct cbcp_addr *addr;
520 addr = (struct cbcp_addr *)data->addr_start;
522 if (data->type == cbcp->fsm.type) {
523 switch (cbcp->fsm.type) {
524 case CBCP_NONUM:
525 return CBCP_ACTION_ACK;
527 case CBCP_CLIENTNUM:
528 if ((char *)data + data->length <= addr->addr)
529 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
530 else if (addr->type != CBCP_ADDR_PSTN)
531 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
532 addr->type);
533 else {
534 strcpy(cbcp->fsm.phone, addr->addr);
535 cbcp->fsm.delay = data->delay;
536 return CBCP_ACTION_ACK;
538 return CBCP_ACTION_DOWN;
540 case CBCP_SERVERNUM:
541 cbcp->fsm.delay = data->delay;
542 return CBCP_ACTION_ACK;
544 case CBCP_LISTNUM:
545 if ((char *)data + data->length <= addr->addr)
546 log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
547 else if (addr->type != CBCP_ADDR_PSTN)
548 log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
549 addr->type);
550 else {
551 char list[sizeof cbcp->fsm.phone], *next;
553 strncpy(list, cbcp->fsm.phone, sizeof list - 1);
554 list[sizeof list - 1] = '\0';
555 for (next = strtok(list, ","); next; next = strtok(NULL, ","))
556 if (!strcmp(addr->addr, next)) {
557 strcpy(cbcp->fsm.phone, next);
558 cbcp->fsm.delay = data->delay;
559 return CBCP_ACTION_ACK;
561 log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
562 "valid number !\n");
564 return CBCP_ACTION_DOWN;
566 log_Printf(LogPHASE, "Internal CBCP error - agreed on %d !\n",
567 (int)cbcp->fsm.type);
568 return CBCP_ACTION_DOWN;
569 } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) {
571 * Client doesn't want CBCP after all....
572 * We only allow this when ``set cbcp *'' has been specified.
574 cbcp->fsm.type = CBCP_NONUM;
575 return CBCP_ACTION_ACK;
577 log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
578 return CBCP_ACTION_REQ;
581 static void
582 cbcp_SendAck(struct cbcp *cbcp)
584 struct cbcp_data data;
585 struct cbcp_addr *addr;
587 /* Only callees send ACKs */
589 log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
590 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
592 data.type = cbcp->fsm.type;
593 switch (data.type) {
594 case CBCP_NONUM:
595 data.length = (char *)&data.delay - (char *)&data;
596 break;
597 case CBCP_CLIENTNUM:
598 addr = (struct cbcp_addr *)data.addr_start;
599 addr->type = CBCP_ADDR_PSTN;
600 strcpy(addr->addr, cbcp->fsm.phone);
601 data.delay = cbcp->fsm.delay;
602 data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data;
603 break;
604 default:
605 data.delay = cbcp->fsm.delay;
606 data.length = data.addr_start - (char *)&data;
607 break;
610 cbcp_data_Show(&data);
611 cbcp_Output(cbcp, CBCP_ACK, &data);
612 cbcp->fsm.restart--;
613 cbcp_StartTimer(cbcp, cbcp->fsm.delay);
614 cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */
617 extern struct mbuf *
618 cbcp_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp)
620 struct physical *p = link2physical(l);
621 struct cbcp_header *head;
622 struct cbcp_data *data;
623 struct cbcp *cbcp = &p->dl->cbcp;
624 size_t len;
626 if (p == NULL) {
627 log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n");
628 m_freem(bp);
629 return NULL;
632 bp = m_pullup(bp);
633 len = m_length(bp);
634 if (len < sizeof(struct cbcp_header)) {
635 m_freem(bp);
636 return NULL;
638 head = (struct cbcp_header *)MBUF_CTOP(bp);
639 if (ntohs(head->length) != len) {
640 log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %u not %zu)"
641 " - ignored\n", head->code, ntohs(head->length), len);
642 m_freem(bp);
643 return NULL;
645 m_settype(bp, MB_CBCPIN);
647 /* XXX check the id */
649 bp->m_offset += sizeof(struct cbcp_header);
650 bp->m_len -= sizeof(struct cbcp_header);
651 data = (struct cbcp_data *)MBUF_CTOP(bp);
653 switch (head->code) {
654 case CBCP_REQ:
655 log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n",
656 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
657 cbcp_data_Show(data);
658 if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) {
659 timer_Stop(&cbcp->fsm.timer);
660 if (cbcp_AdjustResponse(cbcp, data)) {
661 cbcp->fsm.restart = DEF_FSMTRIES;
662 cbcp->fsm.id = head->id;
663 cbcp_SendResponse(cbcp);
664 } else
665 datalink_CBCPFailed(cbcp->p->dl);
666 } else
667 log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name);
668 break;
670 case CBCP_RESPONSE:
671 log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n",
672 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
673 cbcp_data_Show(data);
674 if (cbcp->fsm.id != head->id) {
675 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
676 cbcp->fsm.id, head->id);
677 cbcp->fsm.id = head->id;
679 if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) {
680 timer_Stop(&cbcp->fsm.timer);
681 switch (cbcp_CheckResponse(cbcp, data)) {
682 case CBCP_ACTION_REQ:
683 cbcp_SendReq(cbcp);
684 break;
686 case CBCP_ACTION_ACK:
687 cbcp->fsm.restart = DEF_FSMTRIES;
688 cbcp_SendAck(cbcp);
689 if (cbcp->fsm.type == CBCP_NONUM) {
691 * Don't change state in case the peer doesn't get our ACK,
692 * just bring the layer up.
694 timer_Stop(&cbcp->fsm.timer);
695 datalink_NCPUp(cbcp->p->dl);
697 break;
699 default:
700 datalink_CBCPFailed(cbcp->p->dl);
701 break;
703 } else
704 log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
705 break;
707 case CBCP_ACK:
708 log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n",
709 p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
710 cbcp_data_Show(data);
711 if (cbcp->fsm.id != head->id) {
712 log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
713 cbcp->fsm.id, head->id);
714 cbcp->fsm.id = head->id;
716 if (cbcp->fsm.type == CBCP_NONUM) {
718 * Don't change state in case the peer doesn't get our ACK,
719 * just bring the layer up.
721 timer_Stop(&cbcp->fsm.timer);
722 datalink_NCPUp(cbcp->p->dl);
723 } else if (cbcp->fsm.state == CBCP_RESPSENT) {
724 timer_Stop(&cbcp->fsm.timer);
725 datalink_CBCPComplete(cbcp->p->dl);
726 log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name);
727 } else
728 log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name);
729 break;
731 default:
732 log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %zu)\n",
733 head->code, len);
734 break;
737 m_freem(bp);
738 return NULL;
741 void
742 cbcp_Down(struct cbcp *cbcp)
744 timer_Stop(&cbcp->fsm.timer);
745 cbcp_NewPhase(cbcp, CBCP_CLOSED);
746 cbcp->required = 0;
749 void
750 cbcp_ReceiveTerminateReq(struct physical *p)
752 if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) {
753 /* Don't change our state in case the peer doesn't get the ACK */
754 p->dl->cbcp.required = 1;
755 log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name,
756 p->dl->cbcp.fsm.phone);
757 } else
758 cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED);