xref: /freebsd/usr.sbin/ppp/cbcp.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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