Merge branch 'master' of ssh://swildner@crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / usr.sbin / ppp / cbcp.c
blob670431484bc74fb66911f1ee9fd3622b91402bf9
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 $
27 * $DragonFly: src/usr.sbin/ppp/cbcp.c,v 1.3 2004/02/03 07:11:47 dillon Exp $
30 #include <sys/param.h>
32 #ifdef __DragonFly__
33 #include <netinet/in.h>
34 #endif
35 #include <sys/un.h>
37 #include <string.h>
38 #include <termios.h>
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"
63 void
64 cbcp_Init(struct cbcp *cbcp, struct physical *p)
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;
75 static void cbcp_SendReq(struct cbcp *);
76 static void cbcp_SendResponse(struct cbcp *);
77 static void cbcp_SendAck(struct cbcp *);
79 static void
80 cbcp_Timeout(void *v)
82 struct cbcp *cbcp = (struct cbcp *)v;
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;
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;
103 } else {
104 const char *missed;
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;
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);
132 static void
133 cbcp_StartTimer(struct cbcp *cbcp, int timeout)
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);
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 */
149 static const char * const cbcpname[] = {
150 "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
153 static const char *
154 cbcpstate(int s)
156 if (s < sizeof cbcpname / sizeof cbcpname[0])
157 return cbcpname[s];
158 return HexStr(s, NULL, 0);
161 static void
162 cbcp_NewPhase(struct cbcp *cbcp, int new)
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;
171 struct cbcp_header {
172 u_char code;
173 u_char id;
174 u_int16_t length; /* Network byte order */
178 /* cbcp_header::code values */
179 #define CBCP_REQ (1)
180 #define CBCP_RESPONSE (2)
181 #define CBCP_ACK (3)
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 */
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)
196 static void
197 cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data)
199 struct cbcp_header *head;
200 struct mbuf *bp;
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);
213 static const char *
214 cbcp_data_Type(int type)
216 static const char * const types[] = {
217 "No callback", "User-spec", "Server-spec", "list"
220 if (type < 1 || type > sizeof types / sizeof types[0])
221 return HexStr(type, NULL, 0);
222 return types[type-1];
225 struct cbcp_addr {
226 u_char type;
227 char addr[1]; /* Really ASCIIZ */
230 /* cbcp_data::type values */
231 #define CBCP_ADDR_PSTN (1)
233 static void
234 cbcp_data_Show(struct cbcp_data *data)
236 struct cbcp_addr *addr;
237 char *end;
239 addr = (struct cbcp_addr *)data->addr_start;
240 end = (char *)data + data->length;
241 *end = '\0';
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);
256 static void
257 cbcp_SendReq(struct cbcp *cbcp)
259 struct cbcp_data data;
260 struct cbcp_addr *addr;
261 char list[sizeof cbcp->fsm.phone], *next;
262 int len, max;
264 /* Only callees send REQs */
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';
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;
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);
294 data.length = (char *)addr - (char *)&data;
295 break;
297 case CBCP_SERVERNUM:
298 data.length = data.addr_start - (char *)&data;
299 break;
301 default:
302 data.length = (char *)&data.delay - (char *)&data;
303 break;
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 */
313 void
314 cbcp_Up(struct cbcp *cbcp)
316 struct lcp *lcp = &cbcp->p->link.lcp;
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';
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);
352 static int
353 cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data)
356 * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*)
357 * so that we (hopefully) agree with the peer
359 struct cbcp_addr *addr;
361 switch (data->type) {
362 case CBCP_NONUM:
363 if (cbcp->p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))
365 * if ``none'' is a configured callback possibility
366 * (ie, ``set callback cbcp none''), go along with the callees
367 * request
369 cbcp->fsm.type = CBCP_NONUM;
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....
377 return 1;
379 case CBCP_CLIENTNUM:
380 if (cbcp->fsm.type == CBCP_CLIENTNUM) {
381 char *ptr;
383 if (data->length > data->addr_start - (char *)data) {
385 * The peer has given us an address type spec - make sure we
386 * understand !
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;
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;
401 log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n");
402 return 0;
404 case CBCP_SERVERNUM:
405 if (cbcp->fsm.type == CBCP_SERVERNUM) {
406 *cbcp->fsm.phone = '\0';
407 return 1;
409 if (data->length > data->addr_start - (char *)data) {
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
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) {
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 :-)
427 char list[sizeof cbcp->fsm.phone], *next;
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;
439 log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n");
440 return 0;
442 case CBCP_LISTNUM:
443 if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) {
445 * Search through ``data''s addresses and see if cbcp->fsm.phone
446 * contains any of them
448 char list[sizeof cbcp->fsm.phone], *next, *end;
450 addr = (struct cbcp_addr *)data->addr_start;
451 end = (char *)data + data->length;
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;
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);
469 log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n");
470 return 0;
473 log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type);
474 return 0;
477 static void
478 cbcp_SendResponse(struct cbcp *cbcp)
480 struct cbcp_data data;
481 struct cbcp_addr *addr;
483 /* Only callers send RESPONSEs */
485 log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name,
486 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
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;
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 */
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)
512 static int
513 cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
516 * We've received a RESPONSE (data). Check if it agrees with
517 * our REQ (cbcp->fsm)
519 struct cbcp_addr *addr;
521 addr = (struct cbcp_addr *)data->addr_start;
523 if (data->type == cbcp->fsm.type) {
524 switch (cbcp->fsm.type) {
525 case CBCP_NONUM:
526 return CBCP_ACTION_ACK;
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;
539 return CBCP_ACTION_DOWN;
541 case CBCP_SERVERNUM:
542 cbcp->fsm.delay = data->delay;
543 return CBCP_ACTION_ACK;
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;
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;
562 log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
563 "valid number !\n");
565 return CBCP_ACTION_DOWN;
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) {
572 * Client doesn't want CBCP after all....
573 * We only allow this when ``set cbcp *'' has been specified.
575 cbcp->fsm.type = CBCP_NONUM;
576 return CBCP_ACTION_ACK;
578 log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
579 return CBCP_ACTION_REQ;
582 static void
583 cbcp_SendAck(struct cbcp *cbcp)
585 struct cbcp_data data;
586 struct cbcp_addr *addr;
588 /* Only callees send ACKs */
590 log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
591 cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
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;
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 */
618 extern struct mbuf *
619 cbcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
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;
627 if (p == NULL) {
628 log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n");
629 m_freem(bp);
630 return NULL;
633 bp = m_pullup(bp);
634 len = m_length(bp);
635 if (len < sizeof(struct cbcp_header)) {
636 m_freem(bp);
637 return NULL;
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;
646 m_settype(bp, MB_CBCPIN);
648 /* XXX check the id */
650 bp->m_offset += sizeof(struct cbcp_header);
651 bp->m_len -= sizeof(struct cbcp_header);
652 data = (struct cbcp_data *)MBUF_CTOP(bp);
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;
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;
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;
687 case CBCP_ACTION_ACK:
688 cbcp->fsm.restart = DEF_FSMTRIES;
689 cbcp_SendAck(cbcp);
690 if (cbcp->fsm.type == CBCP_NONUM) {
692 * Don't change state in case the peer doesn't get our ACK,
693 * just bring the layer up.
695 timer_Stop(&cbcp->fsm.timer);
696 datalink_NCPUp(cbcp->p->dl);
698 break;
700 default:
701 datalink_CBCPFailed(cbcp->p->dl);
702 break;
704 } else
705 log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
706 break;
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;
717 if (cbcp->fsm.type == CBCP_NONUM) {
719 * Don't change state in case the peer doesn't get our ACK,
720 * just bring the layer up.
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;
732 default:
733 log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n",
734 head->code, len);
735 break;
738 m_freem(bp);
739 return NULL;
742 void
743 cbcp_Down(struct cbcp *cbcp)
745 timer_Stop(&cbcp->fsm.timer);
746 cbcp_NewPhase(cbcp, CBCP_CLOSED);
747 cbcp->required = 0;
750 void
751 cbcp_ReceiveTerminateReq(struct physical *p)
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);