138175Sbrian/*- 238175Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 338175Sbrian * All rights reserved. 438175Sbrian * 538175Sbrian * Redistribution and use in source and binary forms, with or without 638175Sbrian * modification, are permitted provided that the following conditions 738175Sbrian * are met: 838175Sbrian * 1. Redistributions of source code must retain the above copyright 938175Sbrian * notice, this list of conditions and the following disclaimer. 1038175Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1138175Sbrian * notice, this list of conditions and the following disclaimer in the 1238175Sbrian * documentation and/or other materials provided with the distribution. 1338175Sbrian * 1438175Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538175Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638175Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738175Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838175Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938175Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038175Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138175Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238175Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338175Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438175Sbrian * SUCH DAMAGE. 2538175Sbrian * 2650479Speter * $FreeBSD$ 2738175Sbrian */ 2838175Sbrian 2943313Sbrian#include <sys/param.h> 3038175Sbrian 3196582Sbrian#ifdef __FreeBSD__ 3296582Sbrian#include <netinet/in.h> 3396582Sbrian#endif 3438175Sbrian#include <sys/un.h> 3538175Sbrian 3638175Sbrian#include <string.h> 3738175Sbrian#include <termios.h> 3838175Sbrian 3946686Sbrian#include "layer.h" 4038175Sbrian#include "defs.h" 4138175Sbrian#include "log.h" 4238175Sbrian#include "timer.h" 4338175Sbrian#include "descriptor.h" 4438175Sbrian#include "lqr.h" 4538175Sbrian#include "mbuf.h" 4638175Sbrian#include "fsm.h" 4738175Sbrian#include "throughput.h" 4838175Sbrian#include "hdlc.h" 4963484Sbrian#include "lcp.h" 5038175Sbrian#include "ccp.h" 5138175Sbrian#include "link.h" 5238175Sbrian#include "async.h" 5338175Sbrian#include "physical.h" 5446686Sbrian#include "proto.h" 5538175Sbrian#include "cbcp.h" 5638175Sbrian#include "mp.h" 5738175Sbrian#include "chat.h" 5838175Sbrian#include "auth.h" 5938175Sbrian#include "chap.h" 6038175Sbrian#include "datalink.h" 6138175Sbrian 6238175Sbrianvoid 6338175Sbriancbcp_Init(struct cbcp *cbcp, struct physical *p) 6438175Sbrian{ 6538175Sbrian cbcp->required = 0; 6638175Sbrian cbcp->fsm.state = CBCP_CLOSED; 6738175Sbrian cbcp->fsm.id = 0; 6838175Sbrian cbcp->fsm.delay = 0; 6938175Sbrian *cbcp->fsm.phone = '\0'; 7038175Sbrian memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer); 7138175Sbrian cbcp->p = p; 7238175Sbrian} 7338175Sbrian 7438175Sbrianstatic void cbcp_SendReq(struct cbcp *); 7538175Sbrianstatic void cbcp_SendResponse(struct cbcp *); 7638175Sbrianstatic void cbcp_SendAck(struct cbcp *); 7738175Sbrian 7898243Sbrianstatic void 7938175Sbriancbcp_Timeout(void *v) 8038175Sbrian{ 8138175Sbrian struct cbcp *cbcp = (struct cbcp *)v; 8238175Sbrian 8338175Sbrian timer_Stop(&cbcp->fsm.timer); 8438175Sbrian if (cbcp->fsm.restart) { 8538175Sbrian switch (cbcp->fsm.state) { 8638175Sbrian case CBCP_CLOSED: 8738175Sbrian case CBCP_STOPPED: 8838175Sbrian log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", 8938175Sbrian cbcp->p->dl->name); 9038175Sbrian break; 9138175Sbrian 9238175Sbrian case CBCP_REQSENT: 9338175Sbrian cbcp_SendReq(cbcp); 9438175Sbrian break; 9538175Sbrian case CBCP_RESPSENT: 9638175Sbrian cbcp_SendResponse(cbcp); 9738175Sbrian break; 9838175Sbrian case CBCP_ACKSENT: 9938175Sbrian cbcp_SendAck(cbcp); 10038175Sbrian break; 10138175Sbrian } 10238175Sbrian } else { 10338175Sbrian const char *missed; 10438175Sbrian 10538175Sbrian switch (cbcp->fsm.state) { 10638175Sbrian case CBCP_STOPPED: 10738175Sbrian missed = "REQ"; 10838175Sbrian break; 10938175Sbrian case CBCP_REQSENT: 11038175Sbrian missed = "RESPONSE"; 11138175Sbrian break; 11238175Sbrian case CBCP_RESPSENT: 11338175Sbrian missed = "ACK"; 11438175Sbrian break; 11538175Sbrian case CBCP_ACKSENT: 11638175Sbrian missed = "Terminate REQ"; 11738175Sbrian break; 11838175Sbrian default: 11938175Sbrian log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", 12038175Sbrian cbcp->p->dl->name); 12138175Sbrian missed = NULL; 12238175Sbrian break; 12338175Sbrian } 12438175Sbrian if (missed) 12538175Sbrian log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n", 12638175Sbrian cbcp->p->dl->name, missed); 12738175Sbrian datalink_CBCPFailed(cbcp->p->dl); 12838175Sbrian } 12938175Sbrian} 13038175Sbrian 13138175Sbrianstatic void 13238175Sbriancbcp_StartTimer(struct cbcp *cbcp, int timeout) 13338175Sbrian{ 13438175Sbrian timer_Stop(&cbcp->fsm.timer); 13538175Sbrian cbcp->fsm.timer.func = cbcp_Timeout; 13638175Sbrian cbcp->fsm.timer.name = "cbcp"; 13738175Sbrian cbcp->fsm.timer.load = timeout * SECTICKS; 13838175Sbrian cbcp->fsm.timer.arg = cbcp; 13938175Sbrian timer_Start(&cbcp->fsm.timer); 14038175Sbrian} 14138175Sbrian 14238175Sbrian#define CBCP_CLOSED (0) /* Not in use */ 14338175Sbrian#define CBCP_STOPPED (1) /* Waiting for a REQ */ 14438175Sbrian#define CBCP_REQSENT (2) /* Waiting for a RESP */ 14538175Sbrian#define CBCP_RESPSENT (3) /* Waiting for an ACK */ 14638175Sbrian#define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */ 14738175Sbrian 14855146Sbrianstatic const char * const cbcpname[] = { 14938175Sbrian "closed", "stopped", "req-sent", "resp-sent", "ack-sent" 15038175Sbrian}; 15138175Sbrian 15238175Sbrianstatic const char * 153134789Sbriancbcpstate(unsigned s) 15438175Sbrian{ 15538175Sbrian if (s < sizeof cbcpname / sizeof cbcpname[0]) 15638175Sbrian return cbcpname[s]; 15758034Sbrian return HexStr(s, NULL, 0); 15838175Sbrian} 15938175Sbrian 16038175Sbrianstatic void 16138175Sbriancbcp_NewPhase(struct cbcp *cbcp, int new) 16238175Sbrian{ 16338175Sbrian if (cbcp->fsm.state != new) { 16438175Sbrian log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name, 16538175Sbrian cbcpstate(cbcp->fsm.state), cbcpstate(new)); 16638175Sbrian cbcp->fsm.state = new; 16738175Sbrian } 16838175Sbrian} 16938175Sbrian 17038175Sbrianstruct cbcp_header { 17138175Sbrian u_char code; 17238175Sbrian u_char id; 17338175Sbrian u_int16_t length; /* Network byte order */ 17438175Sbrian}; 17538175Sbrian 17638175Sbrian 17738175Sbrian/* cbcp_header::code values */ 17838175Sbrian#define CBCP_REQ (1) 17938175Sbrian#define CBCP_RESPONSE (2) 18038175Sbrian#define CBCP_ACK (3) 18138175Sbrian 18238175Sbrianstruct cbcp_data { 18338175Sbrian u_char type; 18438175Sbrian u_char length; 18538175Sbrian u_char delay; 18638175Sbrian char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */ 18738175Sbrian}; 18838175Sbrian 18938175Sbrian/* cbcp_data::type values */ 19038175Sbrian#define CBCP_NONUM (1) 19138175Sbrian#define CBCP_CLIENTNUM (2) 19238175Sbrian#define CBCP_SERVERNUM (3) 19338175Sbrian#define CBCP_LISTNUM (4) 19438175Sbrian 19538175Sbrianstatic void 19638175Sbriancbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data) 19738175Sbrian{ 19838175Sbrian struct cbcp_header *head; 19938175Sbrian struct mbuf *bp; 20038175Sbrian 20154912Sbrian bp = m_get(sizeof *head + data->length, MB_CBCPOUT); 20238175Sbrian head = (struct cbcp_header *)MBUF_CTOP(bp); 20338175Sbrian head->code = code; 20438175Sbrian head->id = cbcp->fsm.id; 20538175Sbrian head->length = htons(sizeof *head + data->length); 20638175Sbrian memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length); 20738175Sbrian log_DumpBp(LogDEBUG, "cbcp_Output", bp); 20846686Sbrian link_PushPacket(&cbcp->p->link, bp, cbcp->p->dl->bundle, 20950867Sbrian LINK_QUEUES(&cbcp->p->link) - 1, PROTO_CBCP); 21038175Sbrian} 21138175Sbrian 21238175Sbrianstatic const char * 213134789Sbriancbcp_data_Type(unsigned type) 21438175Sbrian{ 21555146Sbrian static const char * const types[] = { 21638175Sbrian "No callback", "User-spec", "Server-spec", "list" 21738175Sbrian }; 21838175Sbrian 21938175Sbrian if (type < 1 || type > sizeof types / sizeof types[0]) 22058034Sbrian return HexStr(type, NULL, 0); 22138175Sbrian return types[type-1]; 22238175Sbrian} 22338175Sbrian 22438175Sbrianstruct cbcp_addr { 22538175Sbrian u_char type; 226141948Sbrian char addr[sizeof ((struct cbcp_data *)0)->addr_start - 1]; /* ASCIIZ */ 22738175Sbrian}; 22838175Sbrian 22938175Sbrian/* cbcp_data::type values */ 23038175Sbrian#define CBCP_ADDR_PSTN (1) 23138175Sbrian 23238175Sbrianstatic void 23338175Sbriancbcp_data_Show(struct cbcp_data *data) 23438175Sbrian{ 23538175Sbrian struct cbcp_addr *addr; 23638175Sbrian char *end; 23738175Sbrian 23838175Sbrian addr = (struct cbcp_addr *)data->addr_start; 23938175Sbrian end = (char *)data + data->length; 24038175Sbrian *end = '\0'; 24138175Sbrian 24238175Sbrian log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type)); 24338175Sbrian if ((char *)&data->delay < end) { 24438175Sbrian log_Printf(LogCBCP, " DELAY %d\n", data->delay); 24538175Sbrian while (addr->addr < end) { 24638175Sbrian if (addr->type == CBCP_ADDR_PSTN) 24738175Sbrian log_Printf(LogCBCP, " ADDR %s\n", addr->addr); 24838175Sbrian else 24938175Sbrian log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type); 25038175Sbrian addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); 25138175Sbrian } 25238175Sbrian } 25338175Sbrian} 25438175Sbrian 25538175Sbrianstatic void 25638175Sbriancbcp_SendReq(struct cbcp *cbcp) 25738175Sbrian{ 25838175Sbrian struct cbcp_data data; 25938175Sbrian struct cbcp_addr *addr; 26038175Sbrian char list[sizeof cbcp->fsm.phone], *next; 26138175Sbrian int len, max; 26238175Sbrian 26338175Sbrian /* Only callees send REQs */ 26438175Sbrian 26538175Sbrian log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name, 26638175Sbrian cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 26738175Sbrian data.type = cbcp->fsm.type; 26838175Sbrian data.delay = 0; 26938175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 27038175Sbrian list[sizeof list - 1] = '\0'; 27138175Sbrian 27238175Sbrian switch (data.type) { 27338175Sbrian case CBCP_CLIENTNUM: 27438175Sbrian addr = (struct cbcp_addr *)data.addr_start; 27538175Sbrian addr->type = CBCP_ADDR_PSTN; 27638175Sbrian *addr->addr = '\0'; 27738175Sbrian data.length = addr->addr - (char *)&data; 27838175Sbrian break; 27938175Sbrian 28038175Sbrian case CBCP_LISTNUM: 28138175Sbrian addr = (struct cbcp_addr *)data.addr_start; 28238175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { 28338175Sbrian len = strlen(next); 28438175Sbrian max = data.addr_start + sizeof data.addr_start - addr->addr - 1; 28538175Sbrian if (len <= max) { 28638175Sbrian addr->type = CBCP_ADDR_PSTN; 287141948Sbrian strncpy(addr->addr, next, sizeof addr->addr - 1); 288141948Sbrian addr->addr[sizeof addr->addr - 1] = '\0'; 28938175Sbrian addr = (struct cbcp_addr *)((char *)addr + len + 2); 29038175Sbrian } else 29138175Sbrian log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n", 29238175Sbrian next); 29338175Sbrian } 29438175Sbrian data.length = (char *)addr - (char *)&data; 29538175Sbrian break; 29638175Sbrian 29738175Sbrian case CBCP_SERVERNUM: 29838175Sbrian data.length = data.addr_start - (char *)&data; 29938175Sbrian break; 30038175Sbrian 30138175Sbrian default: 30240655Sbrian data.length = (char *)&data.delay - (char *)&data; 30338175Sbrian break; 30438175Sbrian } 30538175Sbrian 30638175Sbrian cbcp_data_Show(&data); 30738175Sbrian cbcp_Output(cbcp, CBCP_REQ, &data); 30838175Sbrian cbcp->fsm.restart--; 30938175Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay); 31038175Sbrian cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */ 31138175Sbrian} 31238175Sbrian 31338175Sbrianvoid 31438175Sbriancbcp_Up(struct cbcp *cbcp) 31538175Sbrian{ 31638175Sbrian struct lcp *lcp = &cbcp->p->link.lcp; 31738175Sbrian 31838175Sbrian cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay; 31938175Sbrian if (*cbcp->p->dl->peer.authname == '\0' || 32038175Sbrian !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone, 32138175Sbrian sizeof cbcp->fsm.phone)) { 32238175Sbrian strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone, 32338175Sbrian sizeof cbcp->fsm.phone - 1); 32438175Sbrian cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0'; 32538175Sbrian } 32638175Sbrian 32738175Sbrian if (lcp->want_callback.opmask) { 32838175Sbrian if (*cbcp->fsm.phone == '\0') 32938175Sbrian cbcp->fsm.type = CBCP_NONUM; 33038175Sbrian else if (!strcmp(cbcp->fsm.phone, "*")) { 33138175Sbrian cbcp->fsm.type = CBCP_SERVERNUM; 33238175Sbrian *cbcp->fsm.phone = '\0'; 33338175Sbrian } else 33438175Sbrian cbcp->fsm.type = CBCP_CLIENTNUM; 33538175Sbrian cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */ 33644305Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_FSMTRIES); 33738175Sbrian } else { 33838175Sbrian if (*cbcp->fsm.phone == '\0') 33938175Sbrian cbcp->fsm.type = CBCP_NONUM; 34038175Sbrian else if (!strcmp(cbcp->fsm.phone, "*")) { 34138175Sbrian cbcp->fsm.type = CBCP_CLIENTNUM; 34238175Sbrian *cbcp->fsm.phone = '\0'; 34338175Sbrian } else if (strchr(cbcp->fsm.phone, ',')) 34438175Sbrian cbcp->fsm.type = CBCP_LISTNUM; 34538175Sbrian else 34638175Sbrian cbcp->fsm.type = CBCP_SERVERNUM; 34744305Sbrian cbcp->fsm.restart = DEF_FSMTRIES; 34838175Sbrian cbcp_SendReq(cbcp); 34938175Sbrian } 35038175Sbrian} 35138175Sbrian 35238175Sbrianstatic int 35338175Sbriancbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data) 35438175Sbrian{ 35538175Sbrian /* 356228990Suqs * We've received a REQ (data). Adjust our response (cbcp->fsm.*) 35738175Sbrian * so that we (hopefully) agree with the peer 35838175Sbrian */ 35938175Sbrian struct cbcp_addr *addr; 36038175Sbrian 36138175Sbrian switch (data->type) { 36238175Sbrian case CBCP_NONUM: 36349132Sbrian if (cbcp->p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) 36449132Sbrian /* 36549132Sbrian * if ``none'' is a configured callback possibility 36649132Sbrian * (ie, ``set callback cbcp none''), go along with the callees 36749132Sbrian * request 36849132Sbrian */ 36949132Sbrian cbcp->fsm.type = CBCP_NONUM; 37049132Sbrian 37140798Sbrian /* 37249132Sbrian * Otherwise, we send our desired response anyway. This seems to be 37349132Sbrian * what Win95 does - although I can't find this behaviour documented 37449132Sbrian * in the CBCP spec.... 37540798Sbrian */ 37649132Sbrian 37740798Sbrian return 1; 37838175Sbrian 37938175Sbrian case CBCP_CLIENTNUM: 38038175Sbrian if (cbcp->fsm.type == CBCP_CLIENTNUM) { 38138175Sbrian char *ptr; 38238175Sbrian 38338175Sbrian if (data->length > data->addr_start - (char *)data) { 38438175Sbrian /* 38538175Sbrian * The peer has given us an address type spec - make sure we 38638175Sbrian * understand ! 38738175Sbrian */ 38838175Sbrian addr = (struct cbcp_addr *)data->addr_start; 38938175Sbrian if (addr->type != CBCP_ADDR_PSTN) { 39038175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 39138175Sbrian (int)addr->type); 39238175Sbrian return 0; 39338175Sbrian } 39438175Sbrian } 39538175Sbrian /* we accept the REQ even if the peer didn't specify an addr->type */ 39638175Sbrian ptr = strchr(cbcp->fsm.phone, ','); 39738175Sbrian if (ptr) 39838175Sbrian *ptr = '\0'; /* Just use the first number in our list */ 39938175Sbrian return 1; 40038175Sbrian } 40138175Sbrian log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n"); 40238175Sbrian return 0; 40338175Sbrian 40438175Sbrian case CBCP_SERVERNUM: 40538175Sbrian if (cbcp->fsm.type == CBCP_SERVERNUM) { 40638175Sbrian *cbcp->fsm.phone = '\0'; 40738175Sbrian return 1; 40838175Sbrian } 40938175Sbrian if (data->length > data->addr_start - (char *)data) { 41038175Sbrian /* 41138175Sbrian * This violates the spec, but if the peer has told us the 41238175Sbrian * number it wants to call back, take advantage of this fact 41338175Sbrian * and allow things to proceed if we've specified the same 41438175Sbrian * number 41538175Sbrian */ 41638175Sbrian addr = (struct cbcp_addr *)data->addr_start; 41738175Sbrian if (addr->type != CBCP_ADDR_PSTN) { 41838175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 41938175Sbrian (int)addr->type); 42038175Sbrian return 0; 42138175Sbrian } else if (cbcp->fsm.type == CBCP_CLIENTNUM) { 42238175Sbrian /* 42338175Sbrian * If the peer's insisting on deciding the number, make sure 42438175Sbrian * it's one of the ones in our list. If it is, let the peer 42538175Sbrian * think it's in control :-) 42638175Sbrian */ 42738175Sbrian char list[sizeof cbcp->fsm.phone], *next; 42838175Sbrian 42938175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 43038175Sbrian list[sizeof list - 1] = '\0'; 43138175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 43238175Sbrian if (!strcmp(next, addr->addr)) { 43338175Sbrian cbcp->fsm.type = CBCP_SERVERNUM; 43438175Sbrian strcpy(cbcp->fsm.phone, next); 43538175Sbrian return 1; 43638175Sbrian } 43738175Sbrian } 43838175Sbrian } 43938175Sbrian log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n"); 44038175Sbrian return 0; 44138175Sbrian 44238175Sbrian case CBCP_LISTNUM: 44338175Sbrian if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) { 44438175Sbrian /* 44538175Sbrian * Search through ``data''s addresses and see if cbcp->fsm.phone 44638175Sbrian * contains any of them 44738175Sbrian */ 44838175Sbrian char list[sizeof cbcp->fsm.phone], *next, *end; 44938175Sbrian 45038175Sbrian addr = (struct cbcp_addr *)data->addr_start; 45138175Sbrian end = (char *)data + data->length; 45238175Sbrian 45338175Sbrian while (addr->addr < end) { 45438175Sbrian if (addr->type == CBCP_ADDR_PSTN) { 45538175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 45638175Sbrian list[sizeof list - 1] = '\0'; 45738175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 45838175Sbrian if (!strcmp(next, addr->addr)) { 45938175Sbrian cbcp->fsm.type = CBCP_LISTNUM; 46038175Sbrian strcpy(cbcp->fsm.phone, next); 46138175Sbrian return 1; 46238175Sbrian } 46338175Sbrian } else 46438175Sbrian log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n", 46538175Sbrian (int)addr->type); 46638175Sbrian addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); 46738175Sbrian } 46838175Sbrian } 46938175Sbrian log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n"); 47038175Sbrian return 0; 47138175Sbrian } 47238175Sbrian 47338175Sbrian log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type); 47438175Sbrian return 0; 47538175Sbrian} 47638175Sbrian 47738175Sbrianstatic void 47838175Sbriancbcp_SendResponse(struct cbcp *cbcp) 47938175Sbrian{ 48038175Sbrian struct cbcp_data data; 48138175Sbrian struct cbcp_addr *addr; 48238175Sbrian 48338175Sbrian /* Only callers send RESPONSEs */ 48438175Sbrian 48538175Sbrian log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name, 48638175Sbrian cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 48738175Sbrian 48838175Sbrian data.type = cbcp->fsm.type; 48938175Sbrian data.delay = cbcp->fsm.delay; 49038175Sbrian addr = (struct cbcp_addr *)data.addr_start; 49140655Sbrian if (data.type == CBCP_NONUM) 49240655Sbrian data.length = (char *)&data.delay - (char *)&data; 49340655Sbrian else if (*cbcp->fsm.phone) { 49438175Sbrian addr->type = CBCP_ADDR_PSTN; 495141948Sbrian strncpy(addr->addr, cbcp->fsm.phone, sizeof addr->addr - 1); 496141948Sbrian addr->addr[sizeof addr->addr - 1] = '\0'; 49738175Sbrian data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data; 49838175Sbrian } else 49938175Sbrian data.length = data.addr_start - (char *)&data; 50038175Sbrian 50138175Sbrian cbcp_data_Show(&data); 50238175Sbrian cbcp_Output(cbcp, CBCP_RESPONSE, &data); 50338175Sbrian cbcp->fsm.restart--; 50438175Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay); 50538175Sbrian cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */ 50638175Sbrian} 50738175Sbrian 50838175Sbrian/* What to do after checking an incoming response */ 50938175Sbrian#define CBCP_ACTION_DOWN (0) 51038175Sbrian#define CBCP_ACTION_REQ (1) 51138175Sbrian#define CBCP_ACTION_ACK (2) 51238175Sbrian 51338175Sbrianstatic int 51438175Sbriancbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data) 51538175Sbrian{ 51638175Sbrian /* 51738175Sbrian * We've received a RESPONSE (data). Check if it agrees with 51838175Sbrian * our REQ (cbcp->fsm) 51938175Sbrian */ 52038175Sbrian struct cbcp_addr *addr; 52138175Sbrian 52238175Sbrian addr = (struct cbcp_addr *)data->addr_start; 52338175Sbrian 52438175Sbrian if (data->type == cbcp->fsm.type) { 52538175Sbrian switch (cbcp->fsm.type) { 52638175Sbrian case CBCP_NONUM: 52738175Sbrian return CBCP_ACTION_ACK; 52838175Sbrian 52938175Sbrian case CBCP_CLIENTNUM: 53038175Sbrian if ((char *)data + data->length <= addr->addr) 53138175Sbrian log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 53238175Sbrian else if (addr->type != CBCP_ADDR_PSTN) 53338175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 53438175Sbrian addr->type); 53538175Sbrian else { 536141948Sbrian strncpy(cbcp->fsm.phone, addr->addr, sizeof cbcp->fsm.phone - 1); 537141948Sbrian cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0'; 53838175Sbrian cbcp->fsm.delay = data->delay; 53938175Sbrian return CBCP_ACTION_ACK; 54038175Sbrian } 54138175Sbrian return CBCP_ACTION_DOWN; 54238175Sbrian 54338175Sbrian case CBCP_SERVERNUM: 54438175Sbrian cbcp->fsm.delay = data->delay; 54538175Sbrian return CBCP_ACTION_ACK; 54638175Sbrian 54738175Sbrian case CBCP_LISTNUM: 54838175Sbrian if ((char *)data + data->length <= addr->addr) 54938175Sbrian log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 55038175Sbrian else if (addr->type != CBCP_ADDR_PSTN) 55138175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 55238175Sbrian addr->type); 55338175Sbrian else { 55438175Sbrian char list[sizeof cbcp->fsm.phone], *next; 55538175Sbrian 55638175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 55738175Sbrian list[sizeof list - 1] = '\0'; 55838175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 55938175Sbrian if (!strcmp(addr->addr, next)) { 56038175Sbrian strcpy(cbcp->fsm.phone, next); 56138175Sbrian cbcp->fsm.delay = data->delay; 56238175Sbrian return CBCP_ACTION_ACK; 56338175Sbrian } 56438175Sbrian log_Printf(LogPHASE, "CBCP: peer didn't respond with a " 56538175Sbrian "valid number !\n"); 56638175Sbrian } 56738175Sbrian return CBCP_ACTION_DOWN; 56838175Sbrian } 56996584Sbrian log_Printf(LogPHASE, "Internal CBCP error - agreed on %d !\n", 57038175Sbrian (int)cbcp->fsm.type); 57138175Sbrian return CBCP_ACTION_DOWN; 57240484Sbrian } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) { 57340484Sbrian /* 57440484Sbrian * Client doesn't want CBCP after all.... 57540484Sbrian * We only allow this when ``set cbcp *'' has been specified. 57640484Sbrian */ 57740484Sbrian cbcp->fsm.type = CBCP_NONUM; 57840484Sbrian return CBCP_ACTION_ACK; 57938175Sbrian } 58038175Sbrian log_Printf(LogCBCP, "Invalid peer RESPONSE\n"); 58138175Sbrian return CBCP_ACTION_REQ; 58238175Sbrian} 58338175Sbrian 58438175Sbrianstatic void 58538175Sbriancbcp_SendAck(struct cbcp *cbcp) 58638175Sbrian{ 58738175Sbrian struct cbcp_data data; 58842842Sbrian struct cbcp_addr *addr; 58938175Sbrian 59038175Sbrian /* Only callees send ACKs */ 59138175Sbrian 59238175Sbrian log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name, 59338175Sbrian cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 59438175Sbrian 59538175Sbrian data.type = cbcp->fsm.type; 59642842Sbrian switch (data.type) { 59742842Sbrian case CBCP_NONUM: 59842842Sbrian data.length = (char *)&data.delay - (char *)&data; 59942842Sbrian break; 60042842Sbrian case CBCP_CLIENTNUM: 60142842Sbrian addr = (struct cbcp_addr *)data.addr_start; 60242842Sbrian addr->type = CBCP_ADDR_PSTN; 603141948Sbrian strncpy(addr->addr, cbcp->fsm.phone, sizeof addr->addr - 1); 604141948Sbrian addr->addr[sizeof addr->addr - 1] = '\0'; 60542842Sbrian data.delay = cbcp->fsm.delay; 60642842Sbrian data.length = addr->addr + strlen(addr->addr) + 1 - (char *)&data; 60742842Sbrian break; 60842842Sbrian default: 60942842Sbrian data.delay = cbcp->fsm.delay; 61042842Sbrian data.length = data.addr_start - (char *)&data; 61142842Sbrian break; 61242842Sbrian } 61338175Sbrian 61438175Sbrian cbcp_data_Show(&data); 61538175Sbrian cbcp_Output(cbcp, CBCP_ACK, &data); 61638175Sbrian cbcp->fsm.restart--; 61738175Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay); 61838175Sbrian cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */ 61938175Sbrian} 62038175Sbrian 62146686Sbrianextern struct mbuf * 622134789Sbriancbcp_Input(struct bundle *bundle __unused, struct link *l, struct mbuf *bp) 62338175Sbrian{ 62446686Sbrian struct physical *p = link2physical(l); 62538175Sbrian struct cbcp_header *head; 62638175Sbrian struct cbcp_data *data; 62738175Sbrian struct cbcp *cbcp = &p->dl->cbcp; 628134789Sbrian size_t len; 62938175Sbrian 63046686Sbrian if (p == NULL) { 63146686Sbrian log_Printf(LogERROR, "cbcp_Input: Not a physical link - dropped\n"); 63254912Sbrian m_freem(bp); 63346686Sbrian return NULL; 63446686Sbrian } 63546686Sbrian 63654912Sbrian bp = m_pullup(bp); 63754912Sbrian len = m_length(bp); 63838175Sbrian if (len < sizeof(struct cbcp_header)) { 63954912Sbrian m_freem(bp); 64046686Sbrian return NULL; 64138175Sbrian } 64238175Sbrian head = (struct cbcp_header *)MBUF_CTOP(bp); 64338175Sbrian if (ntohs(head->length) != len) { 644134833Smarcel log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %u not %zu)" 64538175Sbrian " - ignored\n", head->code, ntohs(head->length), len); 64654912Sbrian m_freem(bp); 64746686Sbrian return NULL; 64838175Sbrian } 64954912Sbrian m_settype(bp, MB_CBCPIN); 65038175Sbrian 65138175Sbrian /* XXX check the id */ 65238175Sbrian 65354912Sbrian bp->m_offset += sizeof(struct cbcp_header); 65454912Sbrian bp->m_len -= sizeof(struct cbcp_header); 65538175Sbrian data = (struct cbcp_data *)MBUF_CTOP(bp); 65638175Sbrian 65738175Sbrian switch (head->code) { 65838175Sbrian case CBCP_REQ: 65938175Sbrian log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n", 66038175Sbrian p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 66138175Sbrian cbcp_data_Show(data); 66238175Sbrian if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) { 66338175Sbrian timer_Stop(&cbcp->fsm.timer); 66438175Sbrian if (cbcp_AdjustResponse(cbcp, data)) { 66544305Sbrian cbcp->fsm.restart = DEF_FSMTRIES; 66640485Sbrian cbcp->fsm.id = head->id; 66738175Sbrian cbcp_SendResponse(cbcp); 66838175Sbrian } else 66938175Sbrian datalink_CBCPFailed(cbcp->p->dl); 67038175Sbrian } else 67138175Sbrian log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name); 67238175Sbrian break; 67338175Sbrian 67438175Sbrian case CBCP_RESPONSE: 67538175Sbrian log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n", 67638175Sbrian p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 67738175Sbrian cbcp_data_Show(data); 67840486Sbrian if (cbcp->fsm.id != head->id) { 67940486Sbrian log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", 68040486Sbrian cbcp->fsm.id, head->id); 68140486Sbrian cbcp->fsm.id = head->id; 68240486Sbrian } 68338175Sbrian if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) { 68438175Sbrian timer_Stop(&cbcp->fsm.timer); 68538175Sbrian switch (cbcp_CheckResponse(cbcp, data)) { 68638175Sbrian case CBCP_ACTION_REQ: 68738175Sbrian cbcp_SendReq(cbcp); 68838175Sbrian break; 68938175Sbrian 69038175Sbrian case CBCP_ACTION_ACK: 69144305Sbrian cbcp->fsm.restart = DEF_FSMTRIES; 69238175Sbrian cbcp_SendAck(cbcp); 69338175Sbrian if (cbcp->fsm.type == CBCP_NONUM) { 69438175Sbrian /* 69538175Sbrian * Don't change state in case the peer doesn't get our ACK, 69638175Sbrian * just bring the layer up. 69738175Sbrian */ 69838175Sbrian timer_Stop(&cbcp->fsm.timer); 69938175Sbrian datalink_NCPUp(cbcp->p->dl); 70038175Sbrian } 70138175Sbrian break; 70238175Sbrian 70338175Sbrian default: 70438175Sbrian datalink_CBCPFailed(cbcp->p->dl); 70538175Sbrian break; 70638175Sbrian } 70738175Sbrian } else 70838175Sbrian log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name); 70938175Sbrian break; 71038175Sbrian 71138175Sbrian case CBCP_ACK: 71238175Sbrian log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n", 71338175Sbrian p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 71438175Sbrian cbcp_data_Show(data); 71540486Sbrian if (cbcp->fsm.id != head->id) { 71640486Sbrian log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", 71740486Sbrian cbcp->fsm.id, head->id); 71840486Sbrian cbcp->fsm.id = head->id; 71940486Sbrian } 72049132Sbrian if (cbcp->fsm.type == CBCP_NONUM) { 72149132Sbrian /* 72249132Sbrian * Don't change state in case the peer doesn't get our ACK, 72349132Sbrian * just bring the layer up. 72449132Sbrian */ 72538175Sbrian timer_Stop(&cbcp->fsm.timer); 72649132Sbrian datalink_NCPUp(cbcp->p->dl); 72749132Sbrian } else if (cbcp->fsm.state == CBCP_RESPSENT) { 72849132Sbrian timer_Stop(&cbcp->fsm.timer); 72938175Sbrian datalink_CBCPComplete(cbcp->p->dl); 73038175Sbrian log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name); 73138175Sbrian } else 73238175Sbrian log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name); 73338175Sbrian break; 73438175Sbrian 73538175Sbrian default: 736134833Smarcel log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %zd)\n", 73738175Sbrian head->code, len); 73838175Sbrian break; 73938175Sbrian } 74038175Sbrian 74154912Sbrian m_freem(bp); 74246686Sbrian return NULL; 74338175Sbrian} 74438175Sbrian 74538175Sbrianvoid 74638175Sbriancbcp_Down(struct cbcp *cbcp) 74738175Sbrian{ 74838175Sbrian timer_Stop(&cbcp->fsm.timer); 74938175Sbrian cbcp_NewPhase(cbcp, CBCP_CLOSED); 75038175Sbrian cbcp->required = 0; 75138175Sbrian} 75238175Sbrian 75338175Sbrianvoid 75438175Sbriancbcp_ReceiveTerminateReq(struct physical *p) 75538175Sbrian{ 75638175Sbrian if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) { 75738175Sbrian /* Don't change our state in case the peer doesn't get the ACK */ 75838175Sbrian p->dl->cbcp.required = 1; 75938175Sbrian log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name, 76038175Sbrian p->dl->cbcp.fsm.phone); 76138175Sbrian } else 76238175Sbrian cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED); 76338175Sbrian} 764