10581dfefSBrian Somers /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
40581dfefSBrian Somers * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
50581dfefSBrian Somers * All rights reserved.
60581dfefSBrian Somers *
70581dfefSBrian Somers * Redistribution and use in source and binary forms, with or without
80581dfefSBrian Somers * modification, are permitted provided that the following conditions
90581dfefSBrian Somers * are met:
100581dfefSBrian Somers * 1. Redistributions of source code must retain the above copyright
110581dfefSBrian Somers * notice, this list of conditions and the following disclaimer.
120581dfefSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
130581dfefSBrian Somers * notice, this list of conditions and the following disclaimer in the
140581dfefSBrian Somers * documentation and/or other materials provided with the distribution.
150581dfefSBrian Somers *
160581dfefSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170581dfefSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180581dfefSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190581dfefSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200581dfefSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210581dfefSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220581dfefSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230581dfefSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240581dfefSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250581dfefSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260581dfefSBrian Somers * SUCH DAMAGE.
270581dfefSBrian Somers */
280581dfefSBrian Somers
29972a1bcfSBrian Somers #include <sys/param.h>
300581dfefSBrian Somers
31de59e178SBrian Somers #ifdef __FreeBSD__
32de59e178SBrian Somers #include <netinet/in.h>
33de59e178SBrian Somers #endif
340581dfefSBrian Somers #include <sys/un.h>
350581dfefSBrian Somers
360581dfefSBrian Somers #include <string.h>
370581dfefSBrian Somers #include <termios.h>
380581dfefSBrian Somers
395d9e6103SBrian Somers #include "layer.h"
400581dfefSBrian Somers #include "defs.h"
410581dfefSBrian Somers #include "log.h"
420581dfefSBrian Somers #include "timer.h"
430581dfefSBrian Somers #include "descriptor.h"
440581dfefSBrian Somers #include "lqr.h"
450581dfefSBrian Somers #include "mbuf.h"
460581dfefSBrian Somers #include "fsm.h"
470581dfefSBrian Somers #include "throughput.h"
480581dfefSBrian Somers #include "hdlc.h"
491038894eSBrian Somers #include "lcp.h"
500581dfefSBrian Somers #include "ccp.h"
510581dfefSBrian Somers #include "link.h"
520581dfefSBrian Somers #include "async.h"
530581dfefSBrian Somers #include "physical.h"
545d9e6103SBrian Somers #include "proto.h"
550581dfefSBrian Somers #include "cbcp.h"
560581dfefSBrian Somers #include "mp.h"
570581dfefSBrian Somers #include "chat.h"
580581dfefSBrian Somers #include "auth.h"
590581dfefSBrian Somers #include "chap.h"
600581dfefSBrian Somers #include "datalink.h"
610581dfefSBrian Somers
620581dfefSBrian Somers void
cbcp_Init(struct cbcp * cbcp,struct physical * p)630581dfefSBrian Somers cbcp_Init(struct cbcp *cbcp, struct physical *p)
640581dfefSBrian Somers {
650581dfefSBrian Somers cbcp->required = 0;
660581dfefSBrian Somers cbcp->fsm.state = CBCP_CLOSED;
670581dfefSBrian Somers cbcp->fsm.id = 0;
680581dfefSBrian Somers cbcp->fsm.delay = 0;
690581dfefSBrian Somers *cbcp->fsm.phone = '\0';
700581dfefSBrian Somers memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer);
710581dfefSBrian Somers cbcp->p = p;
720581dfefSBrian Somers }
730581dfefSBrian Somers
740581dfefSBrian Somers static void cbcp_SendReq(struct cbcp *);
750581dfefSBrian Somers static void cbcp_SendResponse(struct cbcp *);
760581dfefSBrian Somers static void cbcp_SendAck(struct cbcp *);
770581dfefSBrian Somers
780581dfefSBrian Somers static void
cbcp_Timeout(void * v)790581dfefSBrian Somers cbcp_Timeout(void *v)
800581dfefSBrian Somers {
810581dfefSBrian Somers struct cbcp *cbcp = (struct cbcp *)v;
820581dfefSBrian Somers
830581dfefSBrian Somers timer_Stop(&cbcp->fsm.timer);
840581dfefSBrian Somers if (cbcp->fsm.restart) {
850581dfefSBrian Somers switch (cbcp->fsm.state) {
860581dfefSBrian Somers case CBCP_CLOSED:
870581dfefSBrian Somers case CBCP_STOPPED:
880581dfefSBrian Somers log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
890581dfefSBrian Somers cbcp->p->dl->name);
900581dfefSBrian Somers break;
910581dfefSBrian Somers
920581dfefSBrian Somers case CBCP_REQSENT:
930581dfefSBrian Somers cbcp_SendReq(cbcp);
940581dfefSBrian Somers break;
950581dfefSBrian Somers case CBCP_RESPSENT:
960581dfefSBrian Somers cbcp_SendResponse(cbcp);
970581dfefSBrian Somers break;
980581dfefSBrian Somers case CBCP_ACKSENT:
990581dfefSBrian Somers cbcp_SendAck(cbcp);
1000581dfefSBrian Somers break;
1010581dfefSBrian Somers }
1020581dfefSBrian Somers } else {
1030581dfefSBrian Somers const char *missed;
1040581dfefSBrian Somers
1050581dfefSBrian Somers switch (cbcp->fsm.state) {
1060581dfefSBrian Somers case CBCP_STOPPED:
1070581dfefSBrian Somers missed = "REQ";
1080581dfefSBrian Somers break;
1090581dfefSBrian Somers case CBCP_REQSENT:
1100581dfefSBrian Somers missed = "RESPONSE";
1110581dfefSBrian Somers break;
1120581dfefSBrian Somers case CBCP_RESPSENT:
1130581dfefSBrian Somers missed = "ACK";
1140581dfefSBrian Somers break;
1150581dfefSBrian Somers case CBCP_ACKSENT:
1160581dfefSBrian Somers missed = "Terminate REQ";
1170581dfefSBrian Somers break;
1180581dfefSBrian Somers default:
1190581dfefSBrian Somers log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n",
1200581dfefSBrian Somers cbcp->p->dl->name);
1210581dfefSBrian Somers missed = NULL;
1220581dfefSBrian Somers break;
1230581dfefSBrian Somers }
1240581dfefSBrian Somers if (missed)
1250581dfefSBrian Somers log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n",
1260581dfefSBrian Somers cbcp->p->dl->name, missed);
1270581dfefSBrian Somers datalink_CBCPFailed(cbcp->p->dl);
1280581dfefSBrian Somers }
1290581dfefSBrian Somers }
1300581dfefSBrian Somers
1310581dfefSBrian Somers static void
cbcp_StartTimer(struct cbcp * cbcp,int timeout)1320581dfefSBrian Somers cbcp_StartTimer(struct cbcp *cbcp, int timeout)
1330581dfefSBrian Somers {
1340581dfefSBrian Somers timer_Stop(&cbcp->fsm.timer);
1350581dfefSBrian Somers cbcp->fsm.timer.func = cbcp_Timeout;
1360581dfefSBrian Somers cbcp->fsm.timer.name = "cbcp";
1370581dfefSBrian Somers cbcp->fsm.timer.load = timeout * SECTICKS;
1380581dfefSBrian Somers cbcp->fsm.timer.arg = cbcp;
1390581dfefSBrian Somers timer_Start(&cbcp->fsm.timer);
1400581dfefSBrian Somers }
1410581dfefSBrian Somers
1420581dfefSBrian Somers #define CBCP_CLOSED (0) /* Not in use */
1430581dfefSBrian Somers #define CBCP_STOPPED (1) /* Waiting for a REQ */
1440581dfefSBrian Somers #define CBCP_REQSENT (2) /* Waiting for a RESP */
1450581dfefSBrian Somers #define CBCP_RESPSENT (3) /* Waiting for an ACK */
1460581dfefSBrian Somers #define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */
1470581dfefSBrian Somers
148182c898aSBrian Somers static const char * const cbcpname[] = {
1490581dfefSBrian Somers "closed", "stopped", "req-sent", "resp-sent", "ack-sent"
1500581dfefSBrian Somers };
1510581dfefSBrian Somers
1520581dfefSBrian Somers static const char *
cbcpstate(unsigned s)153057f1760SBrian Somers cbcpstate(unsigned s)
1540581dfefSBrian Somers {
1550581dfefSBrian Somers if (s < sizeof cbcpname / sizeof cbcpname[0])
1560581dfefSBrian Somers return cbcpname[s];
157d6d3eeabSBrian Somers return HexStr(s, NULL, 0);
1580581dfefSBrian Somers }
1590581dfefSBrian Somers
1600581dfefSBrian Somers static void
cbcp_NewPhase(struct cbcp * cbcp,int new)1610581dfefSBrian Somers cbcp_NewPhase(struct cbcp *cbcp, int new)
1620581dfefSBrian Somers {
1630581dfefSBrian Somers if (cbcp->fsm.state != new) {
1640581dfefSBrian Somers log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name,
1650581dfefSBrian Somers cbcpstate(cbcp->fsm.state), cbcpstate(new));
1660581dfefSBrian Somers cbcp->fsm.state = new;
1670581dfefSBrian Somers }
1680581dfefSBrian Somers }
1690581dfefSBrian Somers
1700581dfefSBrian Somers struct cbcp_header {
1710581dfefSBrian Somers u_char code;
1720581dfefSBrian Somers u_char id;
1730581dfefSBrian Somers u_int16_t length; /* Network byte order */
1740581dfefSBrian Somers };
1750581dfefSBrian Somers
1760581dfefSBrian Somers
1770581dfefSBrian Somers /* cbcp_header::code values */
1780581dfefSBrian Somers #define CBCP_REQ (1)
1790581dfefSBrian Somers #define CBCP_RESPONSE (2)
1800581dfefSBrian Somers #define CBCP_ACK (3)
1810581dfefSBrian Somers
1820581dfefSBrian Somers struct cbcp_data {
1830581dfefSBrian Somers u_char type;
1840581dfefSBrian Somers u_char length;
1850581dfefSBrian Somers u_char delay;
1860581dfefSBrian Somers char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */
1870581dfefSBrian Somers };
1880581dfefSBrian Somers
1890581dfefSBrian Somers /* cbcp_data::type values */
1900581dfefSBrian Somers #define CBCP_NONUM (1)
1910581dfefSBrian Somers #define CBCP_CLIENTNUM (2)
1920581dfefSBrian Somers #define CBCP_SERVERNUM (3)
1930581dfefSBrian Somers #define CBCP_LISTNUM (4)
1940581dfefSBrian Somers
1950581dfefSBrian Somers static void
cbcp_Output(struct cbcp * cbcp,u_char code,struct cbcp_data * data)1960581dfefSBrian Somers cbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data)
1970581dfefSBrian Somers {
1980581dfefSBrian Somers struct cbcp_header *head;
1990581dfefSBrian Somers struct mbuf *bp;
2000581dfefSBrian Somers
20126af0ae9SBrian Somers bp = m_get(sizeof *head + data->length, MB_CBCPOUT);
2020581dfefSBrian Somers head = (struct cbcp_header *)MBUF_CTOP(bp);
2030581dfefSBrian Somers head->code = code;
2040581dfefSBrian Somers head->id = cbcp->fsm.id;
2050581dfefSBrian Somers head->length = htons(sizeof *head + data->length);
2060581dfefSBrian Somers memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length);
2070581dfefSBrian Somers log_DumpBp(LogDEBUG, "cbcp_Output", bp);
2085d9e6103SBrian Somers link_PushPacket(&cbcp->p->link, bp, cbcp->p->dl->bundle,
209442f8495SBrian Somers LINK_QUEUES(&cbcp->p->link) - 1, PROTO_CBCP);
2100581dfefSBrian Somers }
2110581dfefSBrian Somers
2120581dfefSBrian Somers static const char *
cbcp_data_Type(unsigned type)213057f1760SBrian Somers cbcp_data_Type(unsigned type)
2140581dfefSBrian Somers {
215182c898aSBrian Somers static const char * const types[] = {
2160581dfefSBrian Somers "No callback", "User-spec", "Server-spec", "list"
2170581dfefSBrian Somers };
2180581dfefSBrian Somers
2190581dfefSBrian Somers if (type < 1 || type > sizeof types / sizeof types[0])
220d6d3eeabSBrian Somers return HexStr(type, NULL, 0);
2210581dfefSBrian Somers return types[type-1];
2220581dfefSBrian Somers }
2230581dfefSBrian Somers
2240581dfefSBrian Somers struct cbcp_addr {
2250581dfefSBrian Somers u_char type;
2268ff1207bSBrian Somers char addr[sizeof ((struct cbcp_data *)0)->addr_start - 1]; /* ASCIIZ */
2270581dfefSBrian Somers };
2280581dfefSBrian Somers
2290581dfefSBrian Somers /* cbcp_data::type values */
2300581dfefSBrian Somers #define CBCP_ADDR_PSTN (1)
2310581dfefSBrian Somers
2320581dfefSBrian Somers static void
cbcp_data_Show(struct cbcp_data * data)2330581dfefSBrian Somers cbcp_data_Show(struct cbcp_data *data)
2340581dfefSBrian Somers {
2350581dfefSBrian Somers struct cbcp_addr *addr;
2360581dfefSBrian Somers char *end;
2370581dfefSBrian Somers
2380581dfefSBrian Somers addr = (struct cbcp_addr *)data->addr_start;
2390581dfefSBrian Somers end = (char *)data + data->length;
2400581dfefSBrian Somers *end = '\0';
2410581dfefSBrian Somers
2420581dfefSBrian Somers log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type));
2430581dfefSBrian Somers if ((char *)&data->delay < end) {
2440581dfefSBrian Somers log_Printf(LogCBCP, " DELAY %d\n", data->delay);
2450581dfefSBrian Somers while (addr->addr < end) {
2460581dfefSBrian Somers if (addr->type == CBCP_ADDR_PSTN)
2470581dfefSBrian Somers log_Printf(LogCBCP, " ADDR %s\n", addr->addr);
2480581dfefSBrian Somers else
2490581dfefSBrian Somers log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type);
2500581dfefSBrian Somers addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
2510581dfefSBrian Somers }
2520581dfefSBrian Somers }
2530581dfefSBrian Somers }
2540581dfefSBrian Somers
2550581dfefSBrian Somers static void
cbcp_SendReq(struct cbcp * cbcp)2560581dfefSBrian Somers cbcp_SendReq(struct cbcp *cbcp)
2570581dfefSBrian Somers {
2580581dfefSBrian Somers struct cbcp_data data;
2590581dfefSBrian Somers struct cbcp_addr *addr;
2600581dfefSBrian Somers char list[sizeof cbcp->fsm.phone], *next;
2610581dfefSBrian Somers int len, max;
2620581dfefSBrian Somers
2630581dfefSBrian Somers /* Only callees send REQs */
2640581dfefSBrian Somers
2650581dfefSBrian Somers log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name,
2660581dfefSBrian Somers cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
2670581dfefSBrian Somers data.type = cbcp->fsm.type;
2680581dfefSBrian Somers data.delay = 0;
2690581dfefSBrian Somers strncpy(list, cbcp->fsm.phone, sizeof list - 1);
2700581dfefSBrian Somers list[sizeof list - 1] = '\0';
2710581dfefSBrian Somers
2720581dfefSBrian Somers switch (data.type) {
2730581dfefSBrian Somers case CBCP_CLIENTNUM:
2740581dfefSBrian Somers addr = (struct cbcp_addr *)data.addr_start;
2750581dfefSBrian Somers addr->type = CBCP_ADDR_PSTN;
2760581dfefSBrian Somers *addr->addr = '\0';
2770581dfefSBrian Somers data.length = addr->addr - (char *)&data;
2780581dfefSBrian Somers break;
2790581dfefSBrian Somers
2800581dfefSBrian Somers case CBCP_LISTNUM:
2810581dfefSBrian Somers addr = (struct cbcp_addr *)data.addr_start;
2820581dfefSBrian Somers for (next = strtok(list, ","); next; next = strtok(NULL, ",")) {
2830581dfefSBrian Somers len = strlen(next);
2840581dfefSBrian Somers max = data.addr_start + sizeof data.addr_start - addr->addr - 1;
2850581dfefSBrian Somers if (len <= max) {
2860581dfefSBrian Somers addr->type = CBCP_ADDR_PSTN;
2878ff1207bSBrian Somers strncpy(addr->addr, next, sizeof addr->addr - 1);
2888ff1207bSBrian Somers addr->addr[sizeof addr->addr - 1] = '\0';
2890581dfefSBrian Somers addr = (struct cbcp_addr *)((char *)addr + len + 2);
2900581dfefSBrian Somers } else
2910581dfefSBrian Somers log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n",
2920581dfefSBrian Somers next);
2930581dfefSBrian Somers }
2940581dfefSBrian Somers data.length = (char *)addr - (char *)&data;
2950581dfefSBrian Somers break;
2960581dfefSBrian Somers
2970581dfefSBrian Somers case CBCP_SERVERNUM:
2980581dfefSBrian Somers data.length = data.addr_start - (char *)&data;
2990581dfefSBrian Somers break;
3000581dfefSBrian Somers
3010581dfefSBrian Somers default:
302f6f122b4SBrian Somers data.length = (char *)&data.delay - (char *)&data;
3030581dfefSBrian Somers break;
3040581dfefSBrian Somers }
3050581dfefSBrian Somers
3060581dfefSBrian Somers cbcp_data_Show(&data);
3070581dfefSBrian Somers cbcp_Output(cbcp, CBCP_REQ, &data);
3080581dfefSBrian Somers cbcp->fsm.restart--;
3090581dfefSBrian Somers cbcp_StartTimer(cbcp, cbcp->fsm.delay);
3100581dfefSBrian Somers cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */
3110581dfefSBrian Somers }
3120581dfefSBrian Somers
3130581dfefSBrian Somers void
cbcp_Up(struct cbcp * cbcp)3140581dfefSBrian Somers cbcp_Up(struct cbcp *cbcp)
3150581dfefSBrian Somers {
3160581dfefSBrian Somers struct lcp *lcp = &cbcp->p->link.lcp;
3170581dfefSBrian Somers
3180581dfefSBrian Somers cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay;
3190581dfefSBrian Somers if (*cbcp->p->dl->peer.authname == '\0' ||
3200581dfefSBrian Somers !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone,
3210581dfefSBrian Somers sizeof cbcp->fsm.phone)) {
3220581dfefSBrian Somers strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone,
3230581dfefSBrian Somers sizeof cbcp->fsm.phone - 1);
3240581dfefSBrian Somers cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0';
3250581dfefSBrian Somers }
3260581dfefSBrian Somers
3270581dfefSBrian Somers if (lcp->want_callback.opmask) {
3280581dfefSBrian Somers if (*cbcp->fsm.phone == '\0')
3290581dfefSBrian Somers cbcp->fsm.type = CBCP_NONUM;
3300581dfefSBrian Somers else if (!strcmp(cbcp->fsm.phone, "*")) {
3310581dfefSBrian Somers cbcp->fsm.type = CBCP_SERVERNUM;
3320581dfefSBrian Somers *cbcp->fsm.phone = '\0';
3330581dfefSBrian Somers } else
3340581dfefSBrian Somers cbcp->fsm.type = CBCP_CLIENTNUM;
3350581dfefSBrian Somers cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */
336479508cfSBrian Somers cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_FSMTRIES);
3370581dfefSBrian Somers } else {
3380581dfefSBrian Somers if (*cbcp->fsm.phone == '\0')
3390581dfefSBrian Somers cbcp->fsm.type = CBCP_NONUM;
3400581dfefSBrian Somers else if (!strcmp(cbcp->fsm.phone, "*")) {
3410581dfefSBrian Somers cbcp->fsm.type = CBCP_CLIENTNUM;
3420581dfefSBrian Somers *cbcp->fsm.phone = '\0';
3430581dfefSBrian Somers } else if (strchr(cbcp->fsm.phone, ','))
3440581dfefSBrian Somers cbcp->fsm.type = CBCP_LISTNUM;
3450581dfefSBrian Somers else
3460581dfefSBrian Somers cbcp->fsm.type = CBCP_SERVERNUM;
347479508cfSBrian Somers cbcp->fsm.restart = DEF_FSMTRIES;
3480581dfefSBrian Somers cbcp_SendReq(cbcp);
3490581dfefSBrian Somers }
3500581dfefSBrian Somers }
3510581dfefSBrian Somers
3520581dfefSBrian Somers static int
cbcp_AdjustResponse(struct cbcp * cbcp,struct cbcp_data * data)3530581dfefSBrian Somers cbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data)
3540581dfefSBrian Somers {
3550581dfefSBrian Somers /*
3563df5ecacSUlrich Spörlein * We've received a REQ (data). Adjust our response (cbcp->fsm.*)
3570581dfefSBrian Somers * so that we (hopefully) agree with the peer
3580581dfefSBrian Somers */
3590581dfefSBrian Somers struct cbcp_addr *addr;
3600581dfefSBrian Somers
3610581dfefSBrian Somers switch (data->type) {
3620581dfefSBrian Somers case CBCP_NONUM:
3638d14e328SBrian Somers if (cbcp->p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))
3649fddf73aSBrian Somers /*
3658d14e328SBrian Somers * if ``none'' is a configured callback possibility
3668d14e328SBrian Somers * (ie, ``set callback cbcp none''), go along with the callees
3678d14e328SBrian Somers * request
3689fddf73aSBrian Somers */
3698d14e328SBrian Somers cbcp->fsm.type = CBCP_NONUM;
3708d14e328SBrian Somers
3718d14e328SBrian Somers /*
3728d14e328SBrian Somers * Otherwise, we send our desired response anyway. This seems to be
3738d14e328SBrian Somers * what Win95 does - although I can't find this behaviour documented
3748d14e328SBrian Somers * in the CBCP spec....
3758d14e328SBrian Somers */
3768d14e328SBrian Somers
3770581dfefSBrian Somers return 1;
3780581dfefSBrian Somers
3790581dfefSBrian Somers case CBCP_CLIENTNUM:
3800581dfefSBrian Somers if (cbcp->fsm.type == CBCP_CLIENTNUM) {
3810581dfefSBrian Somers char *ptr;
3820581dfefSBrian Somers
3830581dfefSBrian Somers if (data->length > data->addr_start - (char *)data) {
3840581dfefSBrian Somers /*
3850581dfefSBrian Somers * The peer has given us an address type spec - make sure we
3860581dfefSBrian Somers * understand !
3870581dfefSBrian Somers */
3880581dfefSBrian Somers addr = (struct cbcp_addr *)data->addr_start;
3890581dfefSBrian Somers if (addr->type != CBCP_ADDR_PSTN) {
3900581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
3910581dfefSBrian Somers (int)addr->type);
3920581dfefSBrian Somers return 0;
3930581dfefSBrian Somers }
3940581dfefSBrian Somers }
3950581dfefSBrian Somers /* we accept the REQ even if the peer didn't specify an addr->type */
3960581dfefSBrian Somers ptr = strchr(cbcp->fsm.phone, ',');
3970581dfefSBrian Somers if (ptr)
3980581dfefSBrian Somers *ptr = '\0'; /* Just use the first number in our list */
3990581dfefSBrian Somers return 1;
4000581dfefSBrian Somers }
4010581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n");
4020581dfefSBrian Somers return 0;
4030581dfefSBrian Somers
4040581dfefSBrian Somers case CBCP_SERVERNUM:
4050581dfefSBrian Somers if (cbcp->fsm.type == CBCP_SERVERNUM) {
4060581dfefSBrian Somers *cbcp->fsm.phone = '\0';
4070581dfefSBrian Somers return 1;
4080581dfefSBrian Somers }
4090581dfefSBrian Somers if (data->length > data->addr_start - (char *)data) {
4100581dfefSBrian Somers /*
4110581dfefSBrian Somers * This violates the spec, but if the peer has told us the
4120581dfefSBrian Somers * number it wants to call back, take advantage of this fact
4130581dfefSBrian Somers * and allow things to proceed if we've specified the same
4140581dfefSBrian Somers * number
4150581dfefSBrian Somers */
4160581dfefSBrian Somers addr = (struct cbcp_addr *)data->addr_start;
4170581dfefSBrian Somers if (addr->type != CBCP_ADDR_PSTN) {
4180581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
4190581dfefSBrian Somers (int)addr->type);
4200581dfefSBrian Somers return 0;
4210581dfefSBrian Somers } else if (cbcp->fsm.type == CBCP_CLIENTNUM) {
4220581dfefSBrian Somers /*
4230581dfefSBrian Somers * If the peer's insisting on deciding the number, make sure
4240581dfefSBrian Somers * it's one of the ones in our list. If it is, let the peer
4250581dfefSBrian Somers * think it's in control :-)
4260581dfefSBrian Somers */
4270581dfefSBrian Somers char list[sizeof cbcp->fsm.phone], *next;
4280581dfefSBrian Somers
4290581dfefSBrian Somers strncpy(list, cbcp->fsm.phone, sizeof list - 1);
4300581dfefSBrian Somers list[sizeof list - 1] = '\0';
4310581dfefSBrian Somers for (next = strtok(list, ","); next; next = strtok(NULL, ","))
4320581dfefSBrian Somers if (!strcmp(next, addr->addr)) {
4330581dfefSBrian Somers cbcp->fsm.type = CBCP_SERVERNUM;
4340581dfefSBrian Somers strcpy(cbcp->fsm.phone, next);
4350581dfefSBrian Somers return 1;
4360581dfefSBrian Somers }
4370581dfefSBrian Somers }
4380581dfefSBrian Somers }
4390581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n");
4400581dfefSBrian Somers return 0;
4410581dfefSBrian Somers
4420581dfefSBrian Somers case CBCP_LISTNUM:
4430581dfefSBrian Somers if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) {
4440581dfefSBrian Somers /*
4450581dfefSBrian Somers * Search through ``data''s addresses and see if cbcp->fsm.phone
4460581dfefSBrian Somers * contains any of them
4470581dfefSBrian Somers */
4480581dfefSBrian Somers char list[sizeof cbcp->fsm.phone], *next, *end;
4490581dfefSBrian Somers
4500581dfefSBrian Somers addr = (struct cbcp_addr *)data->addr_start;
4510581dfefSBrian Somers end = (char *)data + data->length;
4520581dfefSBrian Somers
4530581dfefSBrian Somers while (addr->addr < end) {
4540581dfefSBrian Somers if (addr->type == CBCP_ADDR_PSTN) {
4550581dfefSBrian Somers strncpy(list, cbcp->fsm.phone, sizeof list - 1);
4560581dfefSBrian Somers list[sizeof list - 1] = '\0';
4570581dfefSBrian Somers for (next = strtok(list, ","); next; next = strtok(NULL, ","))
4580581dfefSBrian Somers if (!strcmp(next, addr->addr)) {
4590581dfefSBrian Somers cbcp->fsm.type = CBCP_LISTNUM;
4600581dfefSBrian Somers strcpy(cbcp->fsm.phone, next);
4610581dfefSBrian Somers return 1;
4620581dfefSBrian Somers }
4630581dfefSBrian Somers } else
4640581dfefSBrian Somers log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n",
4650581dfefSBrian Somers (int)addr->type);
4660581dfefSBrian Somers addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1);
4670581dfefSBrian Somers }
4680581dfefSBrian Somers }
4690581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n");
4700581dfefSBrian Somers return 0;
4710581dfefSBrian Somers }
4720581dfefSBrian Somers
4730581dfefSBrian Somers log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type);
4740581dfefSBrian Somers return 0;
4750581dfefSBrian Somers }
4760581dfefSBrian Somers
4770581dfefSBrian Somers static void
cbcp_SendResponse(struct cbcp * cbcp)4780581dfefSBrian Somers cbcp_SendResponse(struct cbcp *cbcp)
4790581dfefSBrian Somers {
4800581dfefSBrian Somers struct cbcp_data data;
4810581dfefSBrian Somers struct cbcp_addr *addr;
4820581dfefSBrian Somers
4830581dfefSBrian Somers /* Only callers send RESPONSEs */
4840581dfefSBrian Somers
4850581dfefSBrian Somers log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name,
4860581dfefSBrian Somers cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
4870581dfefSBrian Somers
4880581dfefSBrian Somers data.type = cbcp->fsm.type;
4890581dfefSBrian Somers data.delay = cbcp->fsm.delay;
4900581dfefSBrian Somers addr = (struct cbcp_addr *)data.addr_start;
491f6f122b4SBrian Somers if (data.type == CBCP_NONUM)
492f6f122b4SBrian Somers data.length = (char *)&data.delay - (char *)&data;
493f6f122b4SBrian Somers else if (*cbcp->fsm.phone) {
4940581dfefSBrian Somers addr->type = CBCP_ADDR_PSTN;
4958ff1207bSBrian Somers strncpy(addr->addr, cbcp->fsm.phone, sizeof addr->addr - 1);
4968ff1207bSBrian Somers addr->addr[sizeof addr->addr - 1] = '\0';
4970581dfefSBrian Somers data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data;
4980581dfefSBrian Somers } else
4990581dfefSBrian Somers data.length = data.addr_start - (char *)&data;
5000581dfefSBrian Somers
5010581dfefSBrian Somers cbcp_data_Show(&data);
5020581dfefSBrian Somers cbcp_Output(cbcp, CBCP_RESPONSE, &data);
5030581dfefSBrian Somers cbcp->fsm.restart--;
5040581dfefSBrian Somers cbcp_StartTimer(cbcp, cbcp->fsm.delay);
5050581dfefSBrian Somers cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */
5060581dfefSBrian Somers }
5070581dfefSBrian Somers
5080581dfefSBrian Somers /* What to do after checking an incoming response */
5090581dfefSBrian Somers #define CBCP_ACTION_DOWN (0)
5100581dfefSBrian Somers #define CBCP_ACTION_REQ (1)
5110581dfefSBrian Somers #define CBCP_ACTION_ACK (2)
5120581dfefSBrian Somers
5130581dfefSBrian Somers static int
cbcp_CheckResponse(struct cbcp * cbcp,struct cbcp_data * data)5140581dfefSBrian Somers cbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data)
5150581dfefSBrian Somers {
5160581dfefSBrian Somers /*
5170581dfefSBrian Somers * We've received a RESPONSE (data). Check if it agrees with
5180581dfefSBrian Somers * our REQ (cbcp->fsm)
5190581dfefSBrian Somers */
5200581dfefSBrian Somers struct cbcp_addr *addr;
5210581dfefSBrian Somers
5220581dfefSBrian Somers addr = (struct cbcp_addr *)data->addr_start;
5230581dfefSBrian Somers
5240581dfefSBrian Somers if (data->type == cbcp->fsm.type) {
5250581dfefSBrian Somers switch (cbcp->fsm.type) {
5260581dfefSBrian Somers case CBCP_NONUM:
5270581dfefSBrian Somers return CBCP_ACTION_ACK;
5280581dfefSBrian Somers
5290581dfefSBrian Somers case CBCP_CLIENTNUM:
5300581dfefSBrian Somers if ((char *)data + data->length <= addr->addr)
5310581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
5320581dfefSBrian Somers else if (addr->type != CBCP_ADDR_PSTN)
5330581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
5340581dfefSBrian Somers addr->type);
5350581dfefSBrian Somers else {
5368ff1207bSBrian Somers strncpy(cbcp->fsm.phone, addr->addr, sizeof cbcp->fsm.phone - 1);
5378ff1207bSBrian Somers cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0';
5380581dfefSBrian Somers cbcp->fsm.delay = data->delay;
5390581dfefSBrian Somers return CBCP_ACTION_ACK;
5400581dfefSBrian Somers }
5410581dfefSBrian Somers return CBCP_ACTION_DOWN;
5420581dfefSBrian Somers
5430581dfefSBrian Somers case CBCP_SERVERNUM:
5440581dfefSBrian Somers cbcp->fsm.delay = data->delay;
5450581dfefSBrian Somers return CBCP_ACTION_ACK;
5460581dfefSBrian Somers
5470581dfefSBrian Somers case CBCP_LISTNUM:
5480581dfefSBrian Somers if ((char *)data + data->length <= addr->addr)
5490581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n");
5500581dfefSBrian Somers else if (addr->type != CBCP_ADDR_PSTN)
5510581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n",
5520581dfefSBrian Somers addr->type);
5530581dfefSBrian Somers else {
5540581dfefSBrian Somers char list[sizeof cbcp->fsm.phone], *next;
5550581dfefSBrian Somers
5560581dfefSBrian Somers strncpy(list, cbcp->fsm.phone, sizeof list - 1);
5570581dfefSBrian Somers list[sizeof list - 1] = '\0';
5580581dfefSBrian Somers for (next = strtok(list, ","); next; next = strtok(NULL, ","))
5590581dfefSBrian Somers if (!strcmp(addr->addr, next)) {
5600581dfefSBrian Somers strcpy(cbcp->fsm.phone, next);
5610581dfefSBrian Somers cbcp->fsm.delay = data->delay;
5620581dfefSBrian Somers return CBCP_ACTION_ACK;
5630581dfefSBrian Somers }
5640581dfefSBrian Somers log_Printf(LogPHASE, "CBCP: peer didn't respond with a "
5650581dfefSBrian Somers "valid number !\n");
5660581dfefSBrian Somers }
5670581dfefSBrian Somers return CBCP_ACTION_DOWN;
5680581dfefSBrian Somers }
569d76a0009SBrian Somers log_Printf(LogPHASE, "Internal CBCP error - agreed on %d !\n",
5700581dfefSBrian Somers (int)cbcp->fsm.type);
5710581dfefSBrian Somers return CBCP_ACTION_DOWN;
572f21c8aecSBrian Somers } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) {
573f21c8aecSBrian Somers /*
574f21c8aecSBrian Somers * Client doesn't want CBCP after all....
575f21c8aecSBrian Somers * We only allow this when ``set cbcp *'' has been specified.
576f21c8aecSBrian Somers */
577f21c8aecSBrian Somers cbcp->fsm.type = CBCP_NONUM;
578f21c8aecSBrian Somers return CBCP_ACTION_ACK;
5790581dfefSBrian Somers }
5800581dfefSBrian Somers log_Printf(LogCBCP, "Invalid peer RESPONSE\n");
5810581dfefSBrian Somers return CBCP_ACTION_REQ;
5820581dfefSBrian Somers }
5830581dfefSBrian Somers
5840581dfefSBrian Somers static void
cbcp_SendAck(struct cbcp * cbcp)5850581dfefSBrian Somers cbcp_SendAck(struct cbcp *cbcp)
5860581dfefSBrian Somers {
5870581dfefSBrian Somers struct cbcp_data data;
5888e1fea31SBrian Somers struct cbcp_addr *addr;
5890581dfefSBrian Somers
5900581dfefSBrian Somers /* Only callees send ACKs */
5910581dfefSBrian Somers
5920581dfefSBrian Somers log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name,
5930581dfefSBrian Somers cbcp->fsm.id, cbcpstate(cbcp->fsm.state));
5940581dfefSBrian Somers
5950581dfefSBrian Somers data.type = cbcp->fsm.type;
5968e1fea31SBrian Somers switch (data.type) {
5978e1fea31SBrian Somers case CBCP_NONUM:
5988e1fea31SBrian Somers data.length = (char *)&data.delay - (char *)&data;
5998e1fea31SBrian Somers break;
6008e1fea31SBrian Somers case CBCP_CLIENTNUM:
6018e1fea31SBrian Somers addr = (struct cbcp_addr *)data.addr_start;
6028e1fea31SBrian Somers addr->type = CBCP_ADDR_PSTN;
6038ff1207bSBrian Somers strncpy(addr->addr, cbcp->fsm.phone, sizeof addr->addr - 1);
6048ff1207bSBrian Somers addr->addr[sizeof addr->addr - 1] = '\0';
6050581dfefSBrian Somers data.delay = cbcp->fsm.delay;
6068e1fea31SBrian Somers data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data;
6078e1fea31SBrian Somers break;
6088e1fea31SBrian Somers default:
6098e1fea31SBrian Somers data.delay = cbcp->fsm.delay;
6108e1fea31SBrian Somers data.length = data.addr_start - (char *)&data;
6118e1fea31SBrian Somers break;
6128e1fea31SBrian Somers }
6130581dfefSBrian Somers
6140581dfefSBrian Somers cbcp_data_Show(&data);
6150581dfefSBrian Somers cbcp_Output(cbcp, CBCP_ACK, &data);
6160581dfefSBrian Somers cbcp->fsm.restart--;
6170581dfefSBrian Somers cbcp_StartTimer(cbcp, cbcp->fsm.delay);
6180581dfefSBrian Somers cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */
6190581dfefSBrian Somers }
6200581dfefSBrian Somers
6215d9e6103SBrian Somers extern struct mbuf *
cbcp_Input(struct bundle * bundle __unused,struct link * l,struct mbuf * bp)622057f1760SBrian Somers cbcp_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp)
6230581dfefSBrian Somers {
6245d9e6103SBrian Somers struct physical *p = link2physical(l);
6250581dfefSBrian Somers struct cbcp_header *head;
6260581dfefSBrian Somers struct cbcp_data *data;
6270581dfefSBrian Somers struct cbcp *cbcp = &p->dl->cbcp;
628057f1760SBrian Somers size_t len;
6290581dfefSBrian Somers
6305d9e6103SBrian Somers if (p == NULL) {
6315d9e6103SBrian Somers log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n");
63226af0ae9SBrian Somers m_freem(bp);
6335d9e6103SBrian Somers return NULL;
6345d9e6103SBrian Somers }
6355d9e6103SBrian Somers
63626af0ae9SBrian Somers bp = m_pullup(bp);
63726af0ae9SBrian Somers len = m_length(bp);
6380581dfefSBrian Somers if (len < sizeof(struct cbcp_header)) {
63926af0ae9SBrian Somers m_freem(bp);
6405d9e6103SBrian Somers return NULL;
6410581dfefSBrian Somers }
6420581dfefSBrian Somers head = (struct cbcp_header *)MBUF_CTOP(bp);
6430581dfefSBrian Somers if (ntohs(head->length) != len) {
6441814213eSMarcel Moolenaar log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %u not %zu)"
6450581dfefSBrian Somers " - ignored\n", head->code, ntohs(head->length), len);
64626af0ae9SBrian Somers m_freem(bp);
6475d9e6103SBrian Somers return NULL;
6480581dfefSBrian Somers }
64926af0ae9SBrian Somers m_settype(bp, MB_CBCPIN);
6500581dfefSBrian Somers
6510581dfefSBrian Somers /* XXX check the id */
6520581dfefSBrian Somers
65326af0ae9SBrian Somers bp->m_offset += sizeof(struct cbcp_header);
65426af0ae9SBrian Somers bp->m_len -= sizeof(struct cbcp_header);
6550581dfefSBrian Somers data = (struct cbcp_data *)MBUF_CTOP(bp);
6560581dfefSBrian Somers
6570581dfefSBrian Somers switch (head->code) {
6580581dfefSBrian Somers case CBCP_REQ:
6590581dfefSBrian Somers log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n",
6600581dfefSBrian Somers p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
6610581dfefSBrian Somers cbcp_data_Show(data);
6620581dfefSBrian Somers if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) {
6630581dfefSBrian Somers timer_Stop(&cbcp->fsm.timer);
6640581dfefSBrian Somers if (cbcp_AdjustResponse(cbcp, data)) {
665479508cfSBrian Somers cbcp->fsm.restart = DEF_FSMTRIES;
6660e0c8ee5SBrian Somers cbcp->fsm.id = head->id;
6670581dfefSBrian Somers cbcp_SendResponse(cbcp);
6680581dfefSBrian Somers } else
6690581dfefSBrian Somers datalink_CBCPFailed(cbcp->p->dl);
6700581dfefSBrian Somers } else
6710581dfefSBrian Somers log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name);
6720581dfefSBrian Somers break;
6730581dfefSBrian Somers
6740581dfefSBrian Somers case CBCP_RESPONSE:
6750581dfefSBrian Somers log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n",
6760581dfefSBrian Somers p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
6770581dfefSBrian Somers cbcp_data_Show(data);
678359b5233SBrian Somers if (cbcp->fsm.id != head->id) {
679359b5233SBrian Somers log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
680359b5233SBrian Somers cbcp->fsm.id, head->id);
681359b5233SBrian Somers cbcp->fsm.id = head->id;
682359b5233SBrian Somers }
6830581dfefSBrian Somers if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) {
6840581dfefSBrian Somers timer_Stop(&cbcp->fsm.timer);
6850581dfefSBrian Somers switch (cbcp_CheckResponse(cbcp, data)) {
6860581dfefSBrian Somers case CBCP_ACTION_REQ:
6870581dfefSBrian Somers cbcp_SendReq(cbcp);
6880581dfefSBrian Somers break;
6890581dfefSBrian Somers
6900581dfefSBrian Somers case CBCP_ACTION_ACK:
691479508cfSBrian Somers cbcp->fsm.restart = DEF_FSMTRIES;
6920581dfefSBrian Somers cbcp_SendAck(cbcp);
6930581dfefSBrian Somers if (cbcp->fsm.type == CBCP_NONUM) {
6940581dfefSBrian Somers /*
6950581dfefSBrian Somers * Don't change state in case the peer doesn't get our ACK,
6960581dfefSBrian Somers * just bring the layer up.
6970581dfefSBrian Somers */
6980581dfefSBrian Somers timer_Stop(&cbcp->fsm.timer);
6990581dfefSBrian Somers datalink_NCPUp(cbcp->p->dl);
7000581dfefSBrian Somers }
7010581dfefSBrian Somers break;
7020581dfefSBrian Somers
7030581dfefSBrian Somers default:
7040581dfefSBrian Somers datalink_CBCPFailed(cbcp->p->dl);
7050581dfefSBrian Somers break;
7060581dfefSBrian Somers }
7070581dfefSBrian Somers } else
7080581dfefSBrian Somers log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name);
7090581dfefSBrian Somers break;
7100581dfefSBrian Somers
7110581dfefSBrian Somers case CBCP_ACK:
7120581dfefSBrian Somers log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n",
7130581dfefSBrian Somers p->dl->name, head->id, cbcpstate(cbcp->fsm.state));
7140581dfefSBrian Somers cbcp_data_Show(data);
715359b5233SBrian Somers if (cbcp->fsm.id != head->id) {
716359b5233SBrian Somers log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n",
717359b5233SBrian Somers cbcp->fsm.id, head->id);
718359b5233SBrian Somers cbcp->fsm.id = head->id;
719359b5233SBrian Somers }
7208d14e328SBrian Somers if (cbcp->fsm.type == CBCP_NONUM) {
7218d14e328SBrian Somers /*
7228d14e328SBrian Somers * Don't change state in case the peer doesn't get our ACK,
7238d14e328SBrian Somers * just bring the layer up.
7248d14e328SBrian Somers */
7258d14e328SBrian Somers timer_Stop(&cbcp->fsm.timer);
7268d14e328SBrian Somers datalink_NCPUp(cbcp->p->dl);
7278d14e328SBrian Somers } else if (cbcp->fsm.state == CBCP_RESPSENT) {
7280581dfefSBrian Somers timer_Stop(&cbcp->fsm.timer);
7290581dfefSBrian Somers datalink_CBCPComplete(cbcp->p->dl);
7300581dfefSBrian Somers log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name);
7310581dfefSBrian Somers } else
7320581dfefSBrian Somers log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name);
7330581dfefSBrian Somers break;
7340581dfefSBrian Somers
7350581dfefSBrian Somers default:
7361814213eSMarcel Moolenaar log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %zd)\n",
7370581dfefSBrian Somers head->code, len);
7380581dfefSBrian Somers break;
7390581dfefSBrian Somers }
7400581dfefSBrian Somers
74126af0ae9SBrian Somers m_freem(bp);
7425d9e6103SBrian Somers return NULL;
7430581dfefSBrian Somers }
7440581dfefSBrian Somers
7450581dfefSBrian Somers void
cbcp_Down(struct cbcp * cbcp)7460581dfefSBrian Somers cbcp_Down(struct cbcp *cbcp)
7470581dfefSBrian Somers {
7480581dfefSBrian Somers timer_Stop(&cbcp->fsm.timer);
7490581dfefSBrian Somers cbcp_NewPhase(cbcp, CBCP_CLOSED);
7500581dfefSBrian Somers cbcp->required = 0;
7510581dfefSBrian Somers }
7520581dfefSBrian Somers
7530581dfefSBrian Somers void
cbcp_ReceiveTerminateReq(struct physical * p)7540581dfefSBrian Somers cbcp_ReceiveTerminateReq(struct physical *p)
7550581dfefSBrian Somers {
7560581dfefSBrian Somers if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) {
7570581dfefSBrian Somers /* Don't change our state in case the peer doesn't get the ACK */
7580581dfefSBrian Somers p->dl->cbcp.required = 1;
7590581dfefSBrian Somers log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name,
7600581dfefSBrian Somers p->dl->cbcp.fsm.phone);
7610581dfefSBrian Somers } else
7620581dfefSBrian Somers cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED);
7630581dfefSBrian Somers }
764