cbcp.c revision 40655
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 * 2640655Sbrian * $Id: cbcp.c,v 1.5 1998/10/17 12:28:11 brian Exp $ 2738175Sbrian */ 2838175Sbrian 2938175Sbrian#include <sys/types.h> 3038175Sbrian 3138175Sbrian#include <sys/un.h> 3238175Sbrian 3338175Sbrian#include <string.h> 3438175Sbrian#include <termios.h> 3538175Sbrian 3638175Sbrian#include "defs.h" 3738175Sbrian#include "log.h" 3838175Sbrian#include "timer.h" 3938175Sbrian#include "descriptor.h" 4038175Sbrian#include "lqr.h" 4138175Sbrian#include "mbuf.h" 4238175Sbrian#include "fsm.h" 4338175Sbrian#include "lcp.h" 4438175Sbrian#include "throughput.h" 4538175Sbrian#include "hdlc.h" 4638175Sbrian#include "ccp.h" 4738175Sbrian#include "link.h" 4838175Sbrian#include "async.h" 4938175Sbrian#include "physical.h" 5038175Sbrian#include "lcpproto.h" 5138175Sbrian#include "cbcp.h" 5238175Sbrian#include "mp.h" 5338175Sbrian#include "chat.h" 5438175Sbrian#include "auth.h" 5538175Sbrian#include "chap.h" 5638175Sbrian#include "datalink.h" 5738175Sbrian 5838175Sbrianvoid 5938175Sbriancbcp_Init(struct cbcp *cbcp, struct physical *p) 6038175Sbrian{ 6138175Sbrian cbcp->required = 0; 6238175Sbrian cbcp->fsm.state = CBCP_CLOSED; 6338175Sbrian cbcp->fsm.id = 0; 6438175Sbrian cbcp->fsm.delay = 0; 6538175Sbrian *cbcp->fsm.phone = '\0'; 6638175Sbrian memset(&cbcp->fsm.timer, '\0', sizeof cbcp->fsm.timer); 6738175Sbrian cbcp->p = p; 6838175Sbrian} 6938175Sbrian 7038175Sbrianstatic void cbcp_SendReq(struct cbcp *); 7138175Sbrianstatic void cbcp_SendResponse(struct cbcp *); 7238175Sbrianstatic void cbcp_SendAck(struct cbcp *); 7338175Sbrian 7438175Sbrianstatic void 7538175Sbriancbcp_Timeout(void *v) 7638175Sbrian{ 7738175Sbrian struct cbcp *cbcp = (struct cbcp *)v; 7838175Sbrian 7938175Sbrian timer_Stop(&cbcp->fsm.timer); 8038175Sbrian if (cbcp->fsm.restart) { 8138175Sbrian switch (cbcp->fsm.state) { 8238175Sbrian case CBCP_CLOSED: 8338175Sbrian case CBCP_STOPPED: 8438175Sbrian log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", 8538175Sbrian cbcp->p->dl->name); 8638175Sbrian break; 8738175Sbrian 8838175Sbrian case CBCP_REQSENT: 8938175Sbrian cbcp_SendReq(cbcp); 9038175Sbrian break; 9138175Sbrian case CBCP_RESPSENT: 9238175Sbrian cbcp_SendResponse(cbcp); 9338175Sbrian break; 9438175Sbrian case CBCP_ACKSENT: 9538175Sbrian cbcp_SendAck(cbcp); 9638175Sbrian break; 9738175Sbrian } 9838175Sbrian } else { 9938175Sbrian const char *missed; 10038175Sbrian 10138175Sbrian switch (cbcp->fsm.state) { 10238175Sbrian case CBCP_STOPPED: 10338175Sbrian missed = "REQ"; 10438175Sbrian break; 10538175Sbrian case CBCP_REQSENT: 10638175Sbrian missed = "RESPONSE"; 10738175Sbrian break; 10838175Sbrian case CBCP_RESPSENT: 10938175Sbrian missed = "ACK"; 11038175Sbrian break; 11138175Sbrian case CBCP_ACKSENT: 11238175Sbrian missed = "Terminate REQ"; 11338175Sbrian break; 11438175Sbrian default: 11538175Sbrian log_Printf(LogCBCP, "%s: Urk - unexpected CBCP timeout !\n", 11638175Sbrian cbcp->p->dl->name); 11738175Sbrian missed = NULL; 11838175Sbrian break; 11938175Sbrian } 12038175Sbrian if (missed) 12138175Sbrian log_Printf(LogCBCP, "%s: Timeout waiting for peer %s\n", 12238175Sbrian cbcp->p->dl->name, missed); 12338175Sbrian datalink_CBCPFailed(cbcp->p->dl); 12438175Sbrian } 12538175Sbrian} 12638175Sbrian 12738175Sbrianstatic void 12838175Sbriancbcp_StartTimer(struct cbcp *cbcp, int timeout) 12938175Sbrian{ 13038175Sbrian timer_Stop(&cbcp->fsm.timer); 13138175Sbrian cbcp->fsm.timer.func = cbcp_Timeout; 13238175Sbrian cbcp->fsm.timer.name = "cbcp"; 13338175Sbrian cbcp->fsm.timer.load = timeout * SECTICKS; 13438175Sbrian cbcp->fsm.timer.arg = cbcp; 13538175Sbrian timer_Start(&cbcp->fsm.timer); 13638175Sbrian} 13738175Sbrian 13838175Sbrian#define CBCP_CLOSED (0) /* Not in use */ 13938175Sbrian#define CBCP_STOPPED (1) /* Waiting for a REQ */ 14038175Sbrian#define CBCP_REQSENT (2) /* Waiting for a RESP */ 14138175Sbrian#define CBCP_RESPSENT (3) /* Waiting for an ACK */ 14238175Sbrian#define CBCP_ACKSENT (4) /* Waiting for an LCP Term REQ */ 14338175Sbrian 14438175Sbrianstatic const char *cbcpname[] = { 14538175Sbrian "closed", "stopped", "req-sent", "resp-sent", "ack-sent" 14638175Sbrian}; 14738175Sbrian 14838175Sbrianstatic const char * 14938175Sbriancbcpstate(int s) 15038175Sbrian{ 15138175Sbrian if (s < sizeof cbcpname / sizeof cbcpname[0]) 15238175Sbrian return cbcpname[s]; 15338175Sbrian return "???"; 15438175Sbrian} 15538175Sbrian 15638175Sbrianstatic void 15738175Sbriancbcp_NewPhase(struct cbcp *cbcp, int new) 15838175Sbrian{ 15938175Sbrian if (cbcp->fsm.state != new) { 16038175Sbrian log_Printf(LogCBCP, "%s: State change %s --> %s\n", cbcp->p->dl->name, 16138175Sbrian cbcpstate(cbcp->fsm.state), cbcpstate(new)); 16238175Sbrian cbcp->fsm.state = new; 16338175Sbrian } 16438175Sbrian} 16538175Sbrian 16638175Sbrianstruct cbcp_header { 16738175Sbrian u_char code; 16838175Sbrian u_char id; 16938175Sbrian u_int16_t length; /* Network byte order */ 17038175Sbrian}; 17138175Sbrian 17238175Sbrian 17338175Sbrian/* cbcp_header::code values */ 17438175Sbrian#define CBCP_REQ (1) 17538175Sbrian#define CBCP_RESPONSE (2) 17638175Sbrian#define CBCP_ACK (3) 17738175Sbrian 17838175Sbrianstruct cbcp_data { 17938175Sbrian u_char type; 18038175Sbrian u_char length; 18138175Sbrian u_char delay; 18238175Sbrian char addr_start[253]; /* max cbcp_data length 255 + 1 for NULL */ 18338175Sbrian}; 18438175Sbrian 18538175Sbrian/* cbcp_data::type values */ 18638175Sbrian#define CBCP_NONUM (1) 18738175Sbrian#define CBCP_CLIENTNUM (2) 18838175Sbrian#define CBCP_SERVERNUM (3) 18938175Sbrian#define CBCP_LISTNUM (4) 19038175Sbrian 19138175Sbrianstatic void 19238175Sbriancbcp_Output(struct cbcp *cbcp, u_char code, struct cbcp_data *data) 19338175Sbrian{ 19438175Sbrian struct cbcp_header *head; 19538175Sbrian struct mbuf *bp; 19638175Sbrian 19738175Sbrian bp = mbuf_Alloc(sizeof *head + data->length, MB_CBCP); 19838175Sbrian head = (struct cbcp_header *)MBUF_CTOP(bp); 19938175Sbrian head->code = code; 20038175Sbrian head->id = cbcp->fsm.id; 20138175Sbrian head->length = htons(sizeof *head + data->length); 20238175Sbrian memcpy(MBUF_CTOP(bp) + sizeof *head, data, data->length); 20338175Sbrian log_DumpBp(LogDEBUG, "cbcp_Output", bp); 20438175Sbrian hdlc_Output(&cbcp->p->link, PRI_LINK, PROTO_CBCP, bp); 20538175Sbrian} 20638175Sbrian 20738175Sbrianstatic const char * 20838175Sbriancbcp_data_Type(int type) 20938175Sbrian{ 21038175Sbrian static const char *types[] = { 21138175Sbrian "No callback", "User-spec", "Server-spec", "list" 21238175Sbrian }; 21338175Sbrian 21438175Sbrian if (type < 1 || type > sizeof types / sizeof types[0]) 21538175Sbrian return "???"; 21638175Sbrian return types[type-1]; 21738175Sbrian} 21838175Sbrian 21938175Sbrianstruct cbcp_addr { 22038175Sbrian u_char type; 22138175Sbrian char addr[1]; /* Really ASCIIZ */ 22238175Sbrian}; 22338175Sbrian 22438175Sbrian/* cbcp_data::type values */ 22538175Sbrian#define CBCP_ADDR_PSTN (1) 22638175Sbrian 22738175Sbrianstatic void 22838175Sbriancbcp_data_Show(struct cbcp_data *data) 22938175Sbrian{ 23038175Sbrian struct cbcp_addr *addr; 23138175Sbrian char *end; 23238175Sbrian 23338175Sbrian addr = (struct cbcp_addr *)data->addr_start; 23438175Sbrian end = (char *)data + data->length; 23538175Sbrian *end = '\0'; 23638175Sbrian 23738175Sbrian log_Printf(LogCBCP, " TYPE %s\n", cbcp_data_Type(data->type)); 23838175Sbrian if ((char *)&data->delay < end) { 23938175Sbrian log_Printf(LogCBCP, " DELAY %d\n", data->delay); 24038175Sbrian while (addr->addr < end) { 24138175Sbrian if (addr->type == CBCP_ADDR_PSTN) 24238175Sbrian log_Printf(LogCBCP, " ADDR %s\n", addr->addr); 24338175Sbrian else 24438175Sbrian log_Printf(LogCBCP, " ADDR type %d ??\n", (int)addr->type); 24538175Sbrian addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); 24638175Sbrian } 24738175Sbrian } 24838175Sbrian} 24938175Sbrian 25038175Sbrianstatic void 25138175Sbriancbcp_SendReq(struct cbcp *cbcp) 25238175Sbrian{ 25338175Sbrian struct cbcp_data data; 25438175Sbrian struct cbcp_addr *addr; 25538175Sbrian char list[sizeof cbcp->fsm.phone], *next; 25638175Sbrian int len, max; 25738175Sbrian 25838175Sbrian /* Only callees send REQs */ 25938175Sbrian 26038175Sbrian log_Printf(LogCBCP, "%s: SendReq(%d) state = %s\n", cbcp->p->dl->name, 26138175Sbrian cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 26238175Sbrian data.type = cbcp->fsm.type; 26338175Sbrian data.delay = 0; 26438175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 26538175Sbrian list[sizeof list - 1] = '\0'; 26638175Sbrian 26738175Sbrian switch (data.type) { 26838175Sbrian case CBCP_CLIENTNUM: 26938175Sbrian addr = (struct cbcp_addr *)data.addr_start; 27038175Sbrian addr->type = CBCP_ADDR_PSTN; 27138175Sbrian *addr->addr = '\0'; 27238175Sbrian data.length = addr->addr - (char *)&data; 27338175Sbrian break; 27438175Sbrian 27538175Sbrian case CBCP_LISTNUM: 27638175Sbrian addr = (struct cbcp_addr *)data.addr_start; 27738175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { 27838175Sbrian len = strlen(next); 27938175Sbrian max = data.addr_start + sizeof data.addr_start - addr->addr - 1; 28038175Sbrian if (len <= max) { 28138175Sbrian addr->type = CBCP_ADDR_PSTN; 28238175Sbrian strcpy(addr->addr, next); 28338175Sbrian addr = (struct cbcp_addr *)((char *)addr + len + 2); 28438175Sbrian } else 28538175Sbrian log_Printf(LogWARN, "CBCP ADDR \"%s\" skipped - packet too large\n", 28638175Sbrian next); 28738175Sbrian } 28838175Sbrian data.length = (char *)addr - (char *)&data; 28938175Sbrian break; 29038175Sbrian 29138175Sbrian case CBCP_SERVERNUM: 29238175Sbrian data.length = data.addr_start - (char *)&data; 29338175Sbrian break; 29438175Sbrian 29538175Sbrian default: 29640655Sbrian data.length = (char *)&data.delay - (char *)&data; 29738175Sbrian break; 29838175Sbrian } 29938175Sbrian 30038175Sbrian cbcp_data_Show(&data); 30138175Sbrian cbcp_Output(cbcp, CBCP_REQ, &data); 30238175Sbrian cbcp->fsm.restart--; 30338175Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay); 30438175Sbrian cbcp_NewPhase(cbcp, CBCP_REQSENT); /* Wait for a RESPONSE */ 30538175Sbrian} 30638175Sbrian 30738175Sbrianvoid 30838175Sbriancbcp_Up(struct cbcp *cbcp) 30938175Sbrian{ 31038175Sbrian struct lcp *lcp = &cbcp->p->link.lcp; 31138175Sbrian 31238175Sbrian cbcp->fsm.delay = cbcp->p->dl->cfg.cbcp.delay; 31338175Sbrian if (*cbcp->p->dl->peer.authname == '\0' || 31438175Sbrian !auth_SetPhoneList(cbcp->p->dl->peer.authname, cbcp->fsm.phone, 31538175Sbrian sizeof cbcp->fsm.phone)) { 31638175Sbrian strncpy(cbcp->fsm.phone, cbcp->p->dl->cfg.cbcp.phone, 31738175Sbrian sizeof cbcp->fsm.phone - 1); 31838175Sbrian cbcp->fsm.phone[sizeof cbcp->fsm.phone - 1] = '\0'; 31938175Sbrian } 32038175Sbrian 32138175Sbrian if (lcp->want_callback.opmask) { 32238175Sbrian if (*cbcp->fsm.phone == '\0') 32338175Sbrian cbcp->fsm.type = CBCP_NONUM; 32438175Sbrian else if (!strcmp(cbcp->fsm.phone, "*")) { 32538175Sbrian cbcp->fsm.type = CBCP_SERVERNUM; 32638175Sbrian *cbcp->fsm.phone = '\0'; 32738175Sbrian } else 32838175Sbrian cbcp->fsm.type = CBCP_CLIENTNUM; 32938175Sbrian cbcp_NewPhase(cbcp, CBCP_STOPPED); /* Wait for a REQ */ 33038175Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay * DEF_REQs); 33138175Sbrian } else { 33238175Sbrian if (*cbcp->fsm.phone == '\0') 33338175Sbrian cbcp->fsm.type = CBCP_NONUM; 33438175Sbrian else if (!strcmp(cbcp->fsm.phone, "*")) { 33538175Sbrian cbcp->fsm.type = CBCP_CLIENTNUM; 33638175Sbrian *cbcp->fsm.phone = '\0'; 33738175Sbrian } else if (strchr(cbcp->fsm.phone, ',')) 33838175Sbrian cbcp->fsm.type = CBCP_LISTNUM; 33938175Sbrian else 34038175Sbrian cbcp->fsm.type = CBCP_SERVERNUM; 34138175Sbrian cbcp->fsm.restart = DEF_REQs; 34238175Sbrian cbcp_SendReq(cbcp); 34338175Sbrian } 34438175Sbrian} 34538175Sbrian 34638175Sbrianstatic int 34738175Sbriancbcp_AdjustResponse(struct cbcp *cbcp, struct cbcp_data *data) 34838175Sbrian{ 34938175Sbrian /* 35038175Sbrian * We've received a REQ (data). Adjust our reponse (cbcp->fsm.*) 35138175Sbrian * so that we (hopefully) agree with the peer 35238175Sbrian */ 35338175Sbrian struct cbcp_addr *addr; 35438175Sbrian 35538175Sbrian switch (data->type) { 35638175Sbrian case CBCP_NONUM: 35738175Sbrian if (cbcp->fsm.type == CBCP_NONUM) 35838175Sbrian return 1; 35938175Sbrian log_Printf(LogPHASE, "CBCP: server wants no callback !\n"); 36038175Sbrian return 0; 36138175Sbrian 36238175Sbrian case CBCP_CLIENTNUM: 36338175Sbrian if (cbcp->fsm.type == CBCP_CLIENTNUM) { 36438175Sbrian char *ptr; 36538175Sbrian 36638175Sbrian if (data->length > data->addr_start - (char *)data) { 36738175Sbrian /* 36838175Sbrian * The peer has given us an address type spec - make sure we 36938175Sbrian * understand ! 37038175Sbrian */ 37138175Sbrian addr = (struct cbcp_addr *)data->addr_start; 37238175Sbrian if (addr->type != CBCP_ADDR_PSTN) { 37338175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 37438175Sbrian (int)addr->type); 37538175Sbrian return 0; 37638175Sbrian } 37738175Sbrian } 37838175Sbrian /* we accept the REQ even if the peer didn't specify an addr->type */ 37938175Sbrian ptr = strchr(cbcp->fsm.phone, ','); 38038175Sbrian if (ptr) 38138175Sbrian *ptr = '\0'; /* Just use the first number in our list */ 38238175Sbrian return 1; 38338175Sbrian } 38438175Sbrian log_Printf(LogPHASE, "CBCP: no number to pass to the peer !\n"); 38538175Sbrian return 0; 38638175Sbrian 38738175Sbrian case CBCP_SERVERNUM: 38838175Sbrian if (cbcp->fsm.type == CBCP_SERVERNUM) { 38938175Sbrian *cbcp->fsm.phone = '\0'; 39038175Sbrian return 1; 39138175Sbrian } 39238175Sbrian if (data->length > data->addr_start - (char *)data) { 39338175Sbrian /* 39438175Sbrian * This violates the spec, but if the peer has told us the 39538175Sbrian * number it wants to call back, take advantage of this fact 39638175Sbrian * and allow things to proceed if we've specified the same 39738175Sbrian * number 39838175Sbrian */ 39938175Sbrian addr = (struct cbcp_addr *)data->addr_start; 40038175Sbrian if (addr->type != CBCP_ADDR_PSTN) { 40138175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 40238175Sbrian (int)addr->type); 40338175Sbrian return 0; 40438175Sbrian } else if (cbcp->fsm.type == CBCP_CLIENTNUM) { 40538175Sbrian /* 40638175Sbrian * If the peer's insisting on deciding the number, make sure 40738175Sbrian * it's one of the ones in our list. If it is, let the peer 40838175Sbrian * think it's in control :-) 40938175Sbrian */ 41038175Sbrian char list[sizeof cbcp->fsm.phone], *next; 41138175Sbrian 41238175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 41338175Sbrian list[sizeof list - 1] = '\0'; 41438175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 41538175Sbrian if (!strcmp(next, addr->addr)) { 41638175Sbrian cbcp->fsm.type = CBCP_SERVERNUM; 41738175Sbrian strcpy(cbcp->fsm.phone, next); 41838175Sbrian return 1; 41938175Sbrian } 42038175Sbrian } 42138175Sbrian } 42238175Sbrian log_Printf(LogPHASE, "CBCP: Peer won't allow local decision !\n"); 42338175Sbrian return 0; 42438175Sbrian 42538175Sbrian case CBCP_LISTNUM: 42638175Sbrian if (cbcp->fsm.type == CBCP_CLIENTNUM || cbcp->fsm.type == CBCP_LISTNUM) { 42738175Sbrian /* 42838175Sbrian * Search through ``data''s addresses and see if cbcp->fsm.phone 42938175Sbrian * contains any of them 43038175Sbrian */ 43138175Sbrian char list[sizeof cbcp->fsm.phone], *next, *end; 43238175Sbrian 43338175Sbrian addr = (struct cbcp_addr *)data->addr_start; 43438175Sbrian end = (char *)data + data->length; 43538175Sbrian 43638175Sbrian while (addr->addr < end) { 43738175Sbrian if (addr->type == CBCP_ADDR_PSTN) { 43838175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 43938175Sbrian list[sizeof list - 1] = '\0'; 44038175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 44138175Sbrian if (!strcmp(next, addr->addr)) { 44238175Sbrian cbcp->fsm.type = CBCP_LISTNUM; 44338175Sbrian strcpy(cbcp->fsm.phone, next); 44438175Sbrian return 1; 44538175Sbrian } 44638175Sbrian } else 44738175Sbrian log_Printf(LogCBCP, "Warning: Unrecognised address type %d !\n", 44838175Sbrian (int)addr->type); 44938175Sbrian addr = (struct cbcp_addr *)(addr->addr + strlen(addr->addr) + 1); 45038175Sbrian } 45138175Sbrian } 45238175Sbrian log_Printf(LogPHASE, "CBCP: no good number to pass to the peer !\n"); 45338175Sbrian return 0; 45438175Sbrian } 45538175Sbrian 45638175Sbrian log_Printf(LogCBCP, "Unrecognised REQ type %d !\n", (int)data->type); 45738175Sbrian return 0; 45838175Sbrian} 45938175Sbrian 46038175Sbrianstatic void 46138175Sbriancbcp_SendResponse(struct cbcp *cbcp) 46238175Sbrian{ 46338175Sbrian struct cbcp_data data; 46438175Sbrian struct cbcp_addr *addr; 46538175Sbrian 46638175Sbrian /* Only callers send RESPONSEs */ 46738175Sbrian 46838175Sbrian log_Printf(LogCBCP, "%s: SendResponse(%d) state = %s\n", cbcp->p->dl->name, 46938175Sbrian cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 47038175Sbrian 47138175Sbrian data.type = cbcp->fsm.type; 47238175Sbrian data.delay = cbcp->fsm.delay; 47338175Sbrian addr = (struct cbcp_addr *)data.addr_start; 47440655Sbrian if (data.type == CBCP_NONUM) 47540655Sbrian data.length = (char *)&data.delay - (char *)&data; 47640655Sbrian else if (*cbcp->fsm.phone) { 47738175Sbrian addr->type = CBCP_ADDR_PSTN; 47838175Sbrian strcpy(addr->addr, cbcp->fsm.phone); 47938175Sbrian data.length = (addr->addr + strlen(addr->addr) + 1) - (char *)&data; 48038175Sbrian } else 48138175Sbrian data.length = data.addr_start - (char *)&data; 48238175Sbrian 48338175Sbrian cbcp_data_Show(&data); 48438175Sbrian cbcp_Output(cbcp, CBCP_RESPONSE, &data); 48538175Sbrian cbcp->fsm.restart--; 48638175Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay); 48738175Sbrian cbcp_NewPhase(cbcp, CBCP_RESPSENT); /* Wait for an ACK */ 48838175Sbrian} 48938175Sbrian 49038175Sbrian/* What to do after checking an incoming response */ 49138175Sbrian#define CBCP_ACTION_DOWN (0) 49238175Sbrian#define CBCP_ACTION_REQ (1) 49338175Sbrian#define CBCP_ACTION_ACK (2) 49438175Sbrian 49538175Sbrianstatic int 49638175Sbriancbcp_CheckResponse(struct cbcp *cbcp, struct cbcp_data *data) 49738175Sbrian{ 49838175Sbrian /* 49938175Sbrian * We've received a RESPONSE (data). Check if it agrees with 50038175Sbrian * our REQ (cbcp->fsm) 50138175Sbrian */ 50238175Sbrian struct cbcp_addr *addr; 50338175Sbrian 50438175Sbrian addr = (struct cbcp_addr *)data->addr_start; 50538175Sbrian 50638175Sbrian if (data->type == cbcp->fsm.type) { 50738175Sbrian switch (cbcp->fsm.type) { 50838175Sbrian case CBCP_NONUM: 50938175Sbrian return CBCP_ACTION_ACK; 51038175Sbrian 51138175Sbrian case CBCP_CLIENTNUM: 51238175Sbrian if ((char *)data + data->length <= addr->addr) 51338175Sbrian log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 51438175Sbrian else if (addr->type != CBCP_ADDR_PSTN) 51538175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 51638175Sbrian addr->type); 51738175Sbrian else { 51838175Sbrian strcpy(cbcp->fsm.phone, addr->addr); 51938175Sbrian cbcp->fsm.delay = data->delay; 52038175Sbrian return CBCP_ACTION_ACK; 52138175Sbrian } 52238175Sbrian return CBCP_ACTION_DOWN; 52338175Sbrian 52438175Sbrian case CBCP_SERVERNUM: 52538175Sbrian cbcp->fsm.delay = data->delay; 52638175Sbrian return CBCP_ACTION_ACK; 52738175Sbrian 52838175Sbrian case CBCP_LISTNUM: 52938175Sbrian if ((char *)data + data->length <= addr->addr) 53038175Sbrian log_Printf(LogPHASE, "CBCP: peer didn't respond with a number !\n"); 53138175Sbrian else if (addr->type != CBCP_ADDR_PSTN) 53238175Sbrian log_Printf(LogPHASE, "CBCP: Unrecognised address type %d !\n", 53338175Sbrian addr->type); 53438175Sbrian else { 53538175Sbrian char list[sizeof cbcp->fsm.phone], *next; 53638175Sbrian 53738175Sbrian strncpy(list, cbcp->fsm.phone, sizeof list - 1); 53838175Sbrian list[sizeof list - 1] = '\0'; 53938175Sbrian for (next = strtok(list, ","); next; next = strtok(NULL, ",")) 54038175Sbrian if (!strcmp(addr->addr, next)) { 54138175Sbrian strcpy(cbcp->fsm.phone, next); 54238175Sbrian cbcp->fsm.delay = data->delay; 54338175Sbrian return CBCP_ACTION_ACK; 54438175Sbrian } 54538175Sbrian log_Printf(LogPHASE, "CBCP: peer didn't respond with a " 54638175Sbrian "valid number !\n"); 54738175Sbrian } 54838175Sbrian return CBCP_ACTION_DOWN; 54938175Sbrian } 55038175Sbrian log_Printf(LogPHASE, "Internal CBCP error - agreed on %d ??!?\n", 55138175Sbrian (int)cbcp->fsm.type); 55238175Sbrian return CBCP_ACTION_DOWN; 55340484Sbrian } else if (data->type == CBCP_NONUM && cbcp->fsm.type == CBCP_CLIENTNUM) { 55440484Sbrian /* 55540484Sbrian * Client doesn't want CBCP after all.... 55640484Sbrian * We only allow this when ``set cbcp *'' has been specified. 55740484Sbrian */ 55840484Sbrian cbcp->fsm.type = CBCP_NONUM; 55940484Sbrian return CBCP_ACTION_ACK; 56038175Sbrian } 56138175Sbrian log_Printf(LogCBCP, "Invalid peer RESPONSE\n"); 56238175Sbrian return CBCP_ACTION_REQ; 56338175Sbrian} 56438175Sbrian 56538175Sbrianstatic void 56638175Sbriancbcp_SendAck(struct cbcp *cbcp) 56738175Sbrian{ 56838175Sbrian struct cbcp_data data; 56940655Sbrian char *end; 57038175Sbrian 57138175Sbrian /* Only callees send ACKs */ 57238175Sbrian 57338175Sbrian log_Printf(LogCBCP, "%s: SendAck(%d) state = %s\n", cbcp->p->dl->name, 57438175Sbrian cbcp->fsm.id, cbcpstate(cbcp->fsm.state)); 57538175Sbrian 57638175Sbrian data.type = cbcp->fsm.type; 57738175Sbrian data.delay = cbcp->fsm.delay; 57840655Sbrian end = data.type == CBCP_NONUM ? (char *)&data.delay : data.addr_start; 57940655Sbrian data.length = end - (char *)&data; 58038175Sbrian 58138175Sbrian cbcp_data_Show(&data); 58238175Sbrian cbcp_Output(cbcp, CBCP_ACK, &data); 58338175Sbrian cbcp->fsm.restart--; 58438175Sbrian cbcp_StartTimer(cbcp, cbcp->fsm.delay); 58538175Sbrian cbcp_NewPhase(cbcp, CBCP_ACKSENT); /* Wait for an ACK */ 58638175Sbrian} 58738175Sbrian 58838175Sbrianvoid 58938175Sbriancbcp_Input(struct physical *p, struct mbuf *bp) 59038175Sbrian{ 59138175Sbrian struct cbcp_header *head; 59238175Sbrian struct cbcp_data *data; 59338175Sbrian struct cbcp *cbcp = &p->dl->cbcp; 59438175Sbrian int len; 59538175Sbrian 59638175Sbrian len = mbuf_Length(bp); 59738175Sbrian if (len < sizeof(struct cbcp_header)) { 59838175Sbrian mbuf_Free(bp); 59938175Sbrian return; 60038175Sbrian } 60138175Sbrian head = (struct cbcp_header *)MBUF_CTOP(bp); 60238175Sbrian if (ntohs(head->length) != len) { 60338175Sbrian log_Printf(LogWARN, "Corrupt CBCP packet (code %d, length %d not %d)" 60438175Sbrian " - ignored\n", head->code, ntohs(head->length), len); 60538175Sbrian mbuf_Free(bp); 60638175Sbrian return; 60738175Sbrian } 60838175Sbrian 60938175Sbrian /* XXX check the id */ 61038175Sbrian 61138175Sbrian bp->offset += sizeof(struct cbcp_header); 61238175Sbrian bp->cnt -= sizeof(struct cbcp_header); 61338175Sbrian data = (struct cbcp_data *)MBUF_CTOP(bp); 61438175Sbrian 61538175Sbrian switch (head->code) { 61638175Sbrian case CBCP_REQ: 61738175Sbrian log_Printf(LogCBCP, "%s: RecvReq(%d) state = %s\n", 61838175Sbrian p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 61938175Sbrian cbcp_data_Show(data); 62038175Sbrian if (cbcp->fsm.state == CBCP_STOPPED || cbcp->fsm.state == CBCP_RESPSENT) { 62138175Sbrian timer_Stop(&cbcp->fsm.timer); 62238175Sbrian if (cbcp_AdjustResponse(cbcp, data)) { 62338175Sbrian cbcp->fsm.restart = DEF_REQs; 62440485Sbrian cbcp->fsm.id = head->id; 62538175Sbrian cbcp_SendResponse(cbcp); 62638175Sbrian } else 62738175Sbrian datalink_CBCPFailed(cbcp->p->dl); 62838175Sbrian } else 62938175Sbrian log_Printf(LogCBCP, "%s: unexpected REQ dropped\n", p->dl->name); 63038175Sbrian break; 63138175Sbrian 63238175Sbrian case CBCP_RESPONSE: 63338175Sbrian log_Printf(LogCBCP, "%s: RecvResponse(%d) state = %s\n", 63438175Sbrian p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 63538175Sbrian cbcp_data_Show(data); 63640486Sbrian if (cbcp->fsm.id != head->id) { 63740486Sbrian log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", 63840486Sbrian cbcp->fsm.id, head->id); 63940486Sbrian cbcp->fsm.id = head->id; 64040486Sbrian } 64138175Sbrian if (cbcp->fsm.state == CBCP_REQSENT || cbcp->fsm.state == CBCP_ACKSENT) { 64238175Sbrian timer_Stop(&cbcp->fsm.timer); 64338175Sbrian switch (cbcp_CheckResponse(cbcp, data)) { 64438175Sbrian case CBCP_ACTION_REQ: 64538175Sbrian cbcp_SendReq(cbcp); 64638175Sbrian break; 64738175Sbrian 64838175Sbrian case CBCP_ACTION_ACK: 64938175Sbrian cbcp->fsm.restart = DEF_REQs; 65038175Sbrian cbcp_SendAck(cbcp); 65138175Sbrian if (cbcp->fsm.type == CBCP_NONUM) { 65238175Sbrian /* 65338175Sbrian * Don't change state in case the peer doesn't get our ACK, 65438175Sbrian * just bring the layer up. 65538175Sbrian */ 65638175Sbrian timer_Stop(&cbcp->fsm.timer); 65738175Sbrian datalink_NCPUp(cbcp->p->dl); 65838175Sbrian } 65938175Sbrian break; 66038175Sbrian 66138175Sbrian default: 66238175Sbrian datalink_CBCPFailed(cbcp->p->dl); 66338175Sbrian break; 66438175Sbrian } 66538175Sbrian } else 66638175Sbrian log_Printf(LogCBCP, "%s: unexpected RESPONSE dropped\n", p->dl->name); 66738175Sbrian break; 66838175Sbrian 66938175Sbrian case CBCP_ACK: 67038175Sbrian log_Printf(LogCBCP, "%s: RecvAck(%d) state = %s\n", 67138175Sbrian p->dl->name, head->id, cbcpstate(cbcp->fsm.state)); 67238175Sbrian cbcp_data_Show(data); 67340486Sbrian if (cbcp->fsm.id != head->id) { 67440486Sbrian log_Printf(LogCBCP, "Warning: Expected id was %d, not %d\n", 67540486Sbrian cbcp->fsm.id, head->id); 67640486Sbrian cbcp->fsm.id = head->id; 67740486Sbrian } 67838175Sbrian if (cbcp->fsm.state == CBCP_RESPSENT) { 67938175Sbrian timer_Stop(&cbcp->fsm.timer); 68038175Sbrian datalink_CBCPComplete(cbcp->p->dl); 68138175Sbrian log_Printf(LogPHASE, "%s: CBCP: Peer will dial back\n", p->dl->name); 68238175Sbrian } else 68338175Sbrian log_Printf(LogCBCP, "%s: unexpected ACK dropped\n", p->dl->name); 68438175Sbrian break; 68538175Sbrian 68638175Sbrian default: 68738175Sbrian log_Printf(LogWARN, "Unrecognised CBCP packet (code %d, length %d)\n", 68838175Sbrian head->code, len); 68938175Sbrian break; 69038175Sbrian } 69138175Sbrian 69238175Sbrian mbuf_Free(bp); 69338175Sbrian} 69438175Sbrian 69538175Sbrianvoid 69638175Sbriancbcp_Down(struct cbcp *cbcp) 69738175Sbrian{ 69838175Sbrian timer_Stop(&cbcp->fsm.timer); 69938175Sbrian cbcp_NewPhase(cbcp, CBCP_CLOSED); 70038175Sbrian cbcp->required = 0; 70138175Sbrian} 70238175Sbrian 70338175Sbrianvoid 70438175Sbriancbcp_ReceiveTerminateReq(struct physical *p) 70538175Sbrian{ 70638175Sbrian if (p->dl->cbcp.fsm.state == CBCP_ACKSENT) { 70738175Sbrian /* Don't change our state in case the peer doesn't get the ACK */ 70838175Sbrian p->dl->cbcp.required = 1; 70938175Sbrian log_Printf(LogPHASE, "%s: CBCP: Will dial back on %s\n", p->dl->name, 71038175Sbrian p->dl->cbcp.fsm.phone); 71138175Sbrian } else 71238175Sbrian cbcp_NewPhase(&p->dl->cbcp, CBCP_CLOSED); 71338175Sbrian} 714