165309e5cSBrian Somers /*- 265309e5cSBrian Somers * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 365309e5cSBrian Somers * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 465309e5cSBrian Somers * Internet Initiative Japan, Inc (IIJ) 565309e5cSBrian Somers * All rights reserved. 6af57ed9fSAtsushi Murai * 765309e5cSBrian Somers * Redistribution and use in source and binary forms, with or without 865309e5cSBrian Somers * modification, are permitted provided that the following conditions 965309e5cSBrian Somers * are met: 1065309e5cSBrian Somers * 1. Redistributions of source code must retain the above copyright 1165309e5cSBrian Somers * notice, this list of conditions and the following disclaimer. 1265309e5cSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 1365309e5cSBrian Somers * notice, this list of conditions and the following disclaimer in the 1465309e5cSBrian Somers * documentation and/or other materials provided with the distribution. 15af57ed9fSAtsushi Murai * 1665309e5cSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765309e5cSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865309e5cSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965309e5cSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2065309e5cSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165309e5cSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265309e5cSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365309e5cSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465309e5cSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565309e5cSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665309e5cSBrian Somers * SUCH DAMAGE. 27af57ed9fSAtsushi Murai * 2897d92980SPeter Wemm * $FreeBSD$ 29af57ed9fSAtsushi Murai */ 3065309e5cSBrian Somers 31972a1bcfSBrian Somers #include <sys/param.h> 3275240ed1SBrian Somers #include <netinet/in.h> 33eaa4df37SBrian Somers #include <netinet/in_systm.h> 34eaa4df37SBrian Somers #include <netinet/ip.h> 351fa665f5SBrian Somers #include <sys/un.h> 3675240ed1SBrian Somers 3775240ed1SBrian Somers #include <stdio.h> 3803036ec7SBrian Somers #include <stdlib.h> 39eb6e5e05SBrian Somers #include <string.h> /* memcpy() on some archs */ 4085b542cfSBrian Somers #include <termios.h> 4175240ed1SBrian Somers 425d9e6103SBrian Somers #include "layer.h" 43c9e11a11SBrian Somers #include "defs.h" 44b6e82f33SBrian Somers #include "command.h" 4575240ed1SBrian Somers #include "mbuf.h" 4675240ed1SBrian Somers #include "log.h" 4775240ed1SBrian Somers #include "timer.h" 48af57ed9fSAtsushi Murai #include "fsm.h" 495d9e6103SBrian Somers #include "proto.h" 50ed6a16c1SPoul-Henning Kamp #include "pred.h" 510053cc58SBrian Somers #include "deflate.h" 525828db6dSBrian Somers #include "throughput.h" 535828db6dSBrian Somers #include "iplist.h" 54eaa4df37SBrian Somers #include "slcompress.h" 555a72b6edSBrian Somers #include "lqr.h" 565a72b6edSBrian Somers #include "hdlc.h" 571038894eSBrian Somers #include "lcp.h" 581038894eSBrian Somers #include "ccp.h" 595828db6dSBrian Somers #include "ipcp.h" 605ca5389aSBrian Somers #include "filter.h" 6185b542cfSBrian Somers #include "descriptor.h" 6285b542cfSBrian Somers #include "prompt.h" 63503a7782SBrian Somers #include "link.h" 643b0f8d2eSBrian Somers #include "mp.h" 65ed32233cSBrian Somers #include "async.h" 66ed32233cSBrian Somers #include "physical.h" 67972a1bcfSBrian Somers #ifndef NORADIUS 68972a1bcfSBrian Somers #include "radius.h" 69972a1bcfSBrian Somers #endif 70a8d604abSBrian Somers #ifdef HAVE_DES 71a8d604abSBrian Somers #include "mppe.h" 72a8d604abSBrian Somers #endif 733b0f8d2eSBrian Somers #include "bundle.h" 74af57ed9fSAtsushi Murai 75927145beSBrian Somers static void CcpSendConfigReq(struct fsm *); 762267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *); 772267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char); 7830c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int, 7930c2f2ffSBrian Somers struct fsm_decode *); 80927145beSBrian Somers static void CcpLayerStart(struct fsm *); 81927145beSBrian Somers static void CcpLayerFinish(struct fsm *); 826f384573SBrian Somers static int CcpLayerUp(struct fsm *); 83927145beSBrian Somers static void CcpLayerDown(struct fsm *); 84479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int); 85503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *); 86503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char); 87af57ed9fSAtsushi Murai 8883d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = { 89af57ed9fSAtsushi Murai CcpLayerUp, 90af57ed9fSAtsushi Murai CcpLayerDown, 91af57ed9fSAtsushi Murai CcpLayerStart, 92af57ed9fSAtsushi Murai CcpLayerFinish, 93af57ed9fSAtsushi Murai CcpInitRestartCounter, 94af57ed9fSAtsushi Murai CcpSendConfigReq, 952267893fSBrian Somers CcpSentTerminateReq, 96af57ed9fSAtsushi Murai CcpSendTerminateAck, 97af57ed9fSAtsushi Murai CcpDecodeConfig, 98503a7782SBrian Somers CcpRecvResetReq, 99503a7782SBrian Somers CcpRecvResetAck 100af57ed9fSAtsushi Murai }; 101af57ed9fSAtsushi Murai 102182c898aSBrian Somers static const char * const ccp_TimerNames[] = 1036f384573SBrian Somers {"CCP restart", "CCP openmode", "CCP stopped"}; 1046f384573SBrian Somers 105d6d3eeabSBrian Somers static const char * 106d6d3eeabSBrian Somers protoname(int proto) 107d6d3eeabSBrian Somers { 108182c898aSBrian Somers static char const * const cftypes[] = { 109d6d3eeabSBrian Somers /* Check out the latest ``Compression Control Protocol'' rfc (1962) */ 1109e836af5SBrian Somers "OUI", /* 0: OUI */ 1119e836af5SBrian Somers "PRED1", /* 1: Predictor type 1 */ 1129e836af5SBrian Somers "PRED2", /* 2: Predictor type 2 */ 1139e836af5SBrian Somers "PUDDLE", /* 3: Puddle Jumber */ 114d6d3eeabSBrian Somers NULL, NULL, NULL, NULL, NULL, NULL, 115d6d3eeabSBrian Somers NULL, NULL, NULL, NULL, NULL, NULL, 1169e836af5SBrian Somers "HWPPC", /* 16: Hewlett-Packard PPC */ 1174bc84b8cSBrian Somers "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 118a8d604abSBrian Somers "MPPE", /* 18: Microsoft PPC (rfc2118) and */ 119a8d604abSBrian Somers /* Microsoft PPE (draft-ietf-pppext-mppe) */ 1204bc84b8cSBrian Somers "GAND", /* 19: Gandalf FZA (rfc1993) */ 121b6e82f33SBrian Somers "V42BIS", /* 20: ARG->DATA.42bis compression */ 1220053cc58SBrian Somers "BSD", /* 21: BSD LZW Compress */ 123d6d3eeabSBrian Somers NULL, 1244bc84b8cSBrian Somers "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 1254bc84b8cSBrian Somers "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */ 1261342caedSBrian Somers /* 24: Deflate (according to pppd-2.3.*) */ 1274bc84b8cSBrian Somers "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 1284bc84b8cSBrian Somers "DEFLATE", /* 26: Deflate (rfc1979) */ 129af57ed9fSAtsushi Murai }; 130af57ed9fSAtsushi Murai 131d6d3eeabSBrian Somers if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes || 132d6d3eeabSBrian Somers cftypes[proto] == NULL) 133d6d3eeabSBrian Somers return HexStr(proto, NULL, 0); 1349e836af5SBrian Somers 1350053cc58SBrian Somers return cftypes[proto]; 1360053cc58SBrian Somers } 1370053cc58SBrian Somers 1384bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */ 139182c898aSBrian Somers static const struct ccp_algorithm * const algorithm[] = { 1404bc84b8cSBrian Somers &DeflateAlgorithm, 1410053cc58SBrian Somers &Pred1Algorithm, 1424bc84b8cSBrian Somers &PppdDeflateAlgorithm 143a8d604abSBrian Somers #ifdef HAVE_DES 144a8d604abSBrian Somers , &MPPEAlgorithm 145a8d604abSBrian Somers #endif 1460053cc58SBrian Somers }; 1470053cc58SBrian Somers 14870ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 1490053cc58SBrian Somers 150274e766cSBrian Somers int 151503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg) 152af57ed9fSAtsushi Murai { 153dd0645c5SBrian Somers struct link *l; 154dd0645c5SBrian Somers struct ccp *ccp; 155dd0645c5SBrian Somers 1563a2e4f62SBrian Somers l = command_ChooseLink(arg); 157dd0645c5SBrian Somers ccp = &l->ccp; 158503a7782SBrian Somers 159b6217683SBrian Somers prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, 1601e991daaSBrian Somers State2Nam(ccp->fsm.state)); 1615d9e6103SBrian Somers if (ccp->fsm.state == ST_OPENED) { 162b6217683SBrian Somers prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", 163503a7782SBrian Somers protoname(ccp->my_proto), protoname(ccp->his_proto)); 164b6217683SBrian Somers prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", 165503a7782SBrian Somers ccp->uncompout, ccp->compout, 166503a7782SBrian Somers ccp->compin, ccp->uncompin); 1675d9e6103SBrian Somers } 168cd9647a1SBrian Somers 169b6217683SBrian Somers prompt_Printf(arg->prompt, "\n Defaults: "); 170479508cfSBrian Somers prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config" 171479508cfSBrian Somers " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout, 172479508cfSBrian Somers ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s", 173479508cfSBrian Somers ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s"); 174b6217683SBrian Somers prompt_Printf(arg->prompt, " deflate windows: "); 175b6217683SBrian Somers prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); 176b6217683SBrian Somers prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); 1771342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE: %s\n", 1781342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); 1791342caedSBrian Somers prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", 1801342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); 1811342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE24: %s\n", 1821342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); 183a8d604abSBrian Somers #ifdef HAVE_DES 184ba6fcad9SBrian Somers prompt_Printf(arg->prompt, " MPPE: %s", 185a8d604abSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE])); 186ba6fcad9SBrian Somers prompt_Printf(arg->prompt, " (Key Size = %d-bits)\n", ccp->cfg.mppe.keybits); 187a8d604abSBrian Somers #endif 188274e766cSBrian Somers return 0; 189af57ed9fSAtsushi Murai } 190af57ed9fSAtsushi Murai 1911ae349f5Scvs2svn void 1926f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp) 193af57ed9fSAtsushi Murai { 1946f384573SBrian Somers ccp->fsm.fn = &ccp_Callbacks; 1956f384573SBrian Somers ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; 1966f384573SBrian Somers ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; 1976f384573SBrian Somers ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; 198ea661041SBrian Somers } 199ea661041SBrian Somers 200ea661041SBrian Somers void 2016d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, 2026d666775SBrian Somers const struct fsm_parent *parent) 203ea661041SBrian Somers { 2047308ec68SBrian Somers /* Initialise ourselves */ 2053b0f8d2eSBrian Somers 206479508cfSBrian Somers fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP, 2076f384573SBrian Somers bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); 208cd9647a1SBrian Somers 20903036ec7SBrian Somers ccp->cfg.deflate.in.winsize = 0; 21003036ec7SBrian Somers ccp->cfg.deflate.out.winsize = 15; 211479508cfSBrian Somers ccp->cfg.fsm.timeout = DEF_FSMRETRY; 212479508cfSBrian Somers ccp->cfg.fsm.maxreq = DEF_FSMTRIES; 213479508cfSBrian Somers ccp->cfg.fsm.maxtrm = DEF_FSMTRIES; 2141342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; 2151342caedSBrian Somers ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; 2161342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; 217a8d604abSBrian Somers #ifdef HAVE_DES 218a8d604abSBrian Somers ccp->cfg.mppe.keybits = 128; 219385167a6SBrian Somers ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED; 220a8d604abSBrian Somers #endif 221cd9647a1SBrian Somers 222503a7782SBrian Somers ccp_Setup(ccp); 223503a7782SBrian Somers } 224503a7782SBrian Somers 225503a7782SBrian Somers void 226503a7782SBrian Somers ccp_Setup(struct ccp *ccp) 227503a7782SBrian Somers { 228503a7782SBrian Somers /* Set ourselves up for a startup */ 229503a7782SBrian Somers ccp->fsm.open_mode = 0; 230503a7782SBrian Somers ccp->his_proto = ccp->my_proto = -1; 231503a7782SBrian Somers ccp->reset_sent = ccp->last_reset = -1; 23203036ec7SBrian Somers ccp->in.algorithm = ccp->out.algorithm = -1; 23303036ec7SBrian Somers ccp->in.state = ccp->out.state = NULL; 23403036ec7SBrian Somers ccp->in.opt.id = -1; 23503036ec7SBrian Somers ccp->out.opt = NULL; 236503a7782SBrian Somers ccp->his_reject = ccp->my_reject = 0; 237503a7782SBrian Somers ccp->uncompout = ccp->compout = 0; 238503a7782SBrian Somers ccp->uncompin = ccp->compin = 0; 239af57ed9fSAtsushi Murai } 240af57ed9fSAtsushi Murai 241af57ed9fSAtsushi Murai static void 242479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what) 243af57ed9fSAtsushi Murai { 2447308ec68SBrian Somers /* Set fsm timer load */ 245cd9647a1SBrian Somers struct ccp *ccp = fsm2ccp(fp); 246cd9647a1SBrian Somers 247479508cfSBrian Somers fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS; 248479508cfSBrian Somers switch (what) { 249479508cfSBrian Somers case FSM_REQ_TIMER: 250479508cfSBrian Somers fp->restart = ccp->cfg.fsm.maxreq; 251479508cfSBrian Somers break; 252479508cfSBrian Somers case FSM_TRM_TIMER: 253479508cfSBrian Somers fp->restart = ccp->cfg.fsm.maxtrm; 254479508cfSBrian Somers break; 255479508cfSBrian Somers default: 256479508cfSBrian Somers fp->restart = 1; 257479508cfSBrian Somers break; 258479508cfSBrian Somers } 259af57ed9fSAtsushi Murai } 260af57ed9fSAtsushi Murai 261af57ed9fSAtsushi Murai static void 262944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp) 263af57ed9fSAtsushi Murai { 2647308ec68SBrian Somers /* Send config REQ please */ 265aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 26603036ec7SBrian Somers struct ccp_opt **o; 26730c2f2ffSBrian Somers u_char *cp, buff[100]; 26803036ec7SBrian Somers int f, alloc; 269af57ed9fSAtsushi Murai 27030c2f2ffSBrian Somers cp = buff; 27103036ec7SBrian Somers o = &ccp->out.opt; 27203036ec7SBrian Somers alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; 27383d1af55SBrian Somers ccp->my_proto = -1; 27403036ec7SBrian Somers ccp->out.algorithm = -1; 2750053cc58SBrian Somers for (f = 0; f < NALGORITHMS; f++) 2761342caedSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && 2777f89db65SBrian Somers !REJECTED(ccp, algorithm[f]->id) && 2787f89db65SBrian Somers (*algorithm[f]->Usable)(fp)) { 2790053cc58SBrian Somers 280ba081e43SBrian Somers if (!alloc) 281ba081e43SBrian Somers for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) 282ba081e43SBrian Somers if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) 283ba081e43SBrian Somers break; 284ba081e43SBrian Somers 285ba081e43SBrian Somers if (alloc || *o == NULL) { 28603036ec7SBrian Somers *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); 28703036ec7SBrian Somers (*o)->val.id = algorithm[f]->id; 28803036ec7SBrian Somers (*o)->val.len = 2; 28903036ec7SBrian Somers (*o)->next = NULL; 29003036ec7SBrian Somers (*o)->algorithm = f; 29103036ec7SBrian Somers (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); 292af57ed9fSAtsushi Murai } 2931ae349f5Scvs2svn 29403036ec7SBrian Somers if (cp + (*o)->val.len > buff + sizeof buff) { 295dd7e2610SBrian Somers log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); 29630c2f2ffSBrian Somers break; 29730c2f2ffSBrian Somers } 2982267893fSBrian Somers memcpy(cp, &(*o)->val, (*o)->val.len); 2992267893fSBrian Somers cp += (*o)->val.len; 30003036ec7SBrian Somers 30103036ec7SBrian Somers ccp->my_proto = (*o)->val.id; 30203036ec7SBrian Somers ccp->out.algorithm = f; 30303036ec7SBrian Somers 30403036ec7SBrian Somers if (alloc) 30503036ec7SBrian Somers o = &(*o)->next; 3061ae349f5Scvs2svn } 3072267893fSBrian Somers 308411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT); 309af57ed9fSAtsushi Murai } 310af57ed9fSAtsushi Murai 311af57ed9fSAtsushi Murai void 312dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp) 313af57ed9fSAtsushi Murai { 3147308ec68SBrian Somers /* We can't read our input - ask peer to reset */ 315aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 3162267893fSBrian Somers 31783d1af55SBrian Somers ccp->reset_sent = fp->reqid; 31883d1af55SBrian Somers ccp->last_reset = -1; 319411675baSBrian Somers fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT); 320af57ed9fSAtsushi Murai } 321af57ed9fSAtsushi Murai 322af57ed9fSAtsushi Murai static void 3232267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp) 324af57ed9fSAtsushi Murai { 3257308ec68SBrian Somers /* Term REQ just sent by FSM */ 326af57ed9fSAtsushi Murai } 327af57ed9fSAtsushi Murai 328af57ed9fSAtsushi Murai static void 3292267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id) 330af57ed9fSAtsushi Murai { 3317308ec68SBrian Somers /* Send Term ACK please */ 332411675baSBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT); 333af57ed9fSAtsushi Murai } 334af57ed9fSAtsushi Murai 335503a7782SBrian Somers static void 336944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp) 337af57ed9fSAtsushi Murai { 3387308ec68SBrian Somers /* Got a reset REQ, reset outgoing dictionary */ 339aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 34003036ec7SBrian Somers if (ccp->out.state != NULL) 34103036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); 342af57ed9fSAtsushi Murai } 343af57ed9fSAtsushi Murai 344af57ed9fSAtsushi Murai static void 345944f7098SBrian Somers CcpLayerStart(struct fsm *fp) 346af57ed9fSAtsushi Murai { 3477308ec68SBrian Somers /* We're about to start up ! */ 348479508cfSBrian Somers struct ccp *ccp = fsm2ccp(fp); 349479508cfSBrian Somers 3503a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); 351479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; 352af57ed9fSAtsushi Murai } 353af57ed9fSAtsushi Murai 354af57ed9fSAtsushi Murai static void 355897f9429SBrian Somers CcpLayerDown(struct fsm *fp) 356af57ed9fSAtsushi Murai { 357897f9429SBrian Somers /* About to come down */ 358aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 359ba081e43SBrian Somers struct ccp_opt *next; 360ba081e43SBrian Somers 3613a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); 36203036ec7SBrian Somers if (ccp->in.state != NULL) { 36303036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); 36403036ec7SBrian Somers ccp->in.state = NULL; 3658d9b9867SBrian Somers ccp->in.algorithm = -1; 3667308ec68SBrian Somers } 36703036ec7SBrian Somers if (ccp->out.state != NULL) { 36803036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); 36903036ec7SBrian Somers ccp->out.state = NULL; 3708d9b9867SBrian Somers ccp->out.algorithm = -1; 3717308ec68SBrian Somers } 3728d9b9867SBrian Somers ccp->his_reject = ccp->my_reject = 0; 373ba081e43SBrian Somers 374ba081e43SBrian Somers while (ccp->out.opt) { 375ba081e43SBrian Somers next = ccp->out.opt->next; 376ba081e43SBrian Somers free(ccp->out.opt); 377ba081e43SBrian Somers ccp->out.opt = next; 378ba081e43SBrian Somers } 379897f9429SBrian Somers ccp_Setup(ccp); 380af57ed9fSAtsushi Murai } 381af57ed9fSAtsushi Murai 382af57ed9fSAtsushi Murai static void 383897f9429SBrian Somers CcpLayerFinish(struct fsm *fp) 384af57ed9fSAtsushi Murai { 385897f9429SBrian Somers /* We're now down */ 386e1e8b15eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 387e1e8b15eSBrian Somers struct ccp_opt *next; 388e1e8b15eSBrian Somers 3893a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); 390e1e8b15eSBrian Somers 391e1e8b15eSBrian Somers /* 392e1e8b15eSBrian Somers * Nuke options that may be left over from sending a REQ but never 393e1e8b15eSBrian Somers * coming up. 394e1e8b15eSBrian Somers */ 395e1e8b15eSBrian Somers while (ccp->out.opt) { 396e1e8b15eSBrian Somers next = ccp->out.opt->next; 397e1e8b15eSBrian Somers free(ccp->out.opt); 398e1e8b15eSBrian Somers ccp->out.opt = next; 399e1e8b15eSBrian Somers } 400af57ed9fSAtsushi Murai } 401af57ed9fSAtsushi Murai 4023377c28cSBrian Somers /* Called when CCP has reached the OPEN state */ 4036f384573SBrian Somers static int 404944f7098SBrian Somers CcpLayerUp(struct fsm *fp) 405af57ed9fSAtsushi Murai { 4067308ec68SBrian Somers /* We're now up */ 407aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 408e1e8b15eSBrian Somers struct ccp_opt **o; 409e1e8b15eSBrian Somers int f; 410479508cfSBrian Somers 4113a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); 412479508cfSBrian Somers 41303036ec7SBrian Somers if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 41403036ec7SBrian Somers ccp->in.algorithm < NALGORITHMS) { 41503036ec7SBrian Somers ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 41603036ec7SBrian Somers if (ccp->in.state == NULL) { 417dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", 418d47dceb8SBrian Somers fp->link->name, protoname(ccp->his_proto)); 41983d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 420dd7e2610SBrian Somers fsm_Close(fp); 421479508cfSBrian Somers return 0; 42279d1bdaeSBrian Somers } 423af57ed9fSAtsushi Murai } 424af57ed9fSAtsushi Murai 425e1e8b15eSBrian Somers o = &ccp->out.opt; 426e1e8b15eSBrian Somers for (f = 0; f < ccp->out.algorithm; f++) 427e1e8b15eSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg])) 428e1e8b15eSBrian Somers o = &(*o)->next; 429e1e8b15eSBrian Somers 43003036ec7SBrian Somers if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 43103036ec7SBrian Somers ccp->out.algorithm < NALGORITHMS) { 432e1e8b15eSBrian Somers ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)(&(*o)->val); 43303036ec7SBrian Somers if (ccp->out.state == NULL) { 434dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", 435d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto)); 43683d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 437dd7e2610SBrian Somers fsm_Close(fp); 438479508cfSBrian Somers return 0; 439247ab36dSBrian Somers } 440af57ed9fSAtsushi Murai } 441af57ed9fSAtsushi Murai 442479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; 443479508cfSBrian Somers 444dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 445d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 44683d1af55SBrian Somers protoname(ccp->his_proto), ccp->his_proto); 447479508cfSBrian Somers 4486f384573SBrian Somers return 1; 449af57ed9fSAtsushi Murai } 450af57ed9fSAtsushi Murai 451af57ed9fSAtsushi Murai static void 45230c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 45330c2f2ffSBrian Somers struct fsm_decode *dec) 454af57ed9fSAtsushi Murai { 4557308ec68SBrian Somers /* Deal with incoming data */ 456aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 45731516407SBrian Somers int type, length, f; 45803036ec7SBrian Somers const char *end; 459af57ed9fSAtsushi Murai 46031516407SBrian Somers if (mode_type == MODE_REQ) 46131516407SBrian Somers ccp->in.algorithm = -1; /* In case we've received two REQs in a row */ 46231516407SBrian Somers 463af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 464af57ed9fSAtsushi Murai type = *cp; 465af57ed9fSAtsushi Murai length = cp[1]; 46603036ec7SBrian Somers 467d47dceb8SBrian Somers if (length == 0) { 468dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); 469d47dceb8SBrian Somers break; 470d47dceb8SBrian Somers } 471d47dceb8SBrian Somers 47203036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 47303036ec7SBrian Somers length = sizeof(struct lcp_opt); 474dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", 475d47dceb8SBrian Somers fp->link->name, length); 47603036ec7SBrian Somers } 477af57ed9fSAtsushi Murai 4780053cc58SBrian Somers for (f = NALGORITHMS-1; f > -1; f--) 4790053cc58SBrian Somers if (algorithm[f]->id == type) 4800053cc58SBrian Somers break; 481af57ed9fSAtsushi Murai 48203036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 48303036ec7SBrian Somers if (end == NULL) 48403036ec7SBrian Somers end = ""; 48503036ec7SBrian Somers 486d6d3eeabSBrian Somers log_Printf(LogCCP, " %s[%d] %s\n", protoname(type), length, end); 48703036ec7SBrian Somers 4880053cc58SBrian Somers if (f == -1) { 4890053cc58SBrian Somers /* Don't understand that :-( */ 4900053cc58SBrian Somers if (mode_type == MODE_REQ) { 49183d1af55SBrian Somers ccp->my_reject |= (1 << type); 49230c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 49330c2f2ffSBrian Somers dec->rejend += length; 4940053cc58SBrian Somers } 4950053cc58SBrian Somers } else { 49603036ec7SBrian Somers struct ccp_opt *o; 4970053cc58SBrian Somers 4989780ef31SBrian Somers switch (mode_type) { 499af57ed9fSAtsushi Murai case MODE_REQ: 5001342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 5017f89db65SBrian Somers (*algorithm[f]->Usable)(fp) && 5021342caedSBrian Somers ccp->in.algorithm == -1) { 50303036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 50403036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 5050053cc58SBrian Somers case MODE_REJ: 50603036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 50703036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 5080053cc58SBrian Somers break; 5090053cc58SBrian Somers case MODE_NAK: 51003036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 51103036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 5120053cc58SBrian Somers break; 5130053cc58SBrian Somers case MODE_ACK: 51430c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 51530c2f2ffSBrian Somers dec->ackend += length; 51683d1af55SBrian Somers ccp->his_proto = type; 51703036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 5180053cc58SBrian Somers break; 5190053cc58SBrian Somers } 520af57ed9fSAtsushi Murai } else { 52130c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 52230c2f2ffSBrian Somers dec->rejend += length; 523af57ed9fSAtsushi Murai } 524af57ed9fSAtsushi Murai break; 525af57ed9fSAtsushi Murai case MODE_NAK: 52603036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 52703036ec7SBrian Somers if (o->val.id == cp[0]) 52803036ec7SBrian Somers break; 52903036ec7SBrian Somers if (o == NULL) 5309b996792SBrian Somers log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent" 5319b996792SBrian Somers " option\n", fp->link->name); 5320053cc58SBrian Somers else { 53303036ec7SBrian Somers memcpy(&o->val, cp, length); 53403036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 53583d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 5361ae349f5Scvs2svn else { 53783d1af55SBrian Somers ccp->his_reject |= (1 << type); 53883d1af55SBrian Somers ccp->my_proto = -1; 5391ae349f5Scvs2svn } 5400053cc58SBrian Somers } 5410053cc58SBrian Somers break; 542af57ed9fSAtsushi Murai case MODE_REJ: 54383d1af55SBrian Somers ccp->his_reject |= (1 << type); 54483d1af55SBrian Somers ccp->my_proto = -1; 545af57ed9fSAtsushi Murai break; 546af57ed9fSAtsushi Murai } 547af57ed9fSAtsushi Murai } 5480053cc58SBrian Somers 54903036ec7SBrian Somers plen -= cp[1]; 55003036ec7SBrian Somers cp += cp[1]; 551af57ed9fSAtsushi Murai } 5520053cc58SBrian Somers 553e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 5541342caedSBrian Somers if (dec->rejend != dec->rej) { 55503036ec7SBrian Somers /* rejects are preferred */ 55603036ec7SBrian Somers dec->ackend = dec->ack; 55703036ec7SBrian Somers dec->nakend = dec->nak; 55803036ec7SBrian Somers if (ccp->in.state == NULL) { 55983d1af55SBrian Somers ccp->his_proto = -1; 56003036ec7SBrian Somers ccp->in.algorithm = -1; 56103036ec7SBrian Somers } 5621342caedSBrian Somers } else if (dec->nakend != dec->nak) { 56303036ec7SBrian Somers /* then NAKs */ 56403036ec7SBrian Somers dec->ackend = dec->ack; 56503036ec7SBrian Somers if (ccp->in.state == NULL) { 56603036ec7SBrian Somers ccp->his_proto = -1; 56703036ec7SBrian Somers ccp->in.algorithm = -1; 568247ab36dSBrian Somers } 5691ae349f5Scvs2svn } 5700053cc58SBrian Somers } 571af57ed9fSAtsushi Murai } 572af57ed9fSAtsushi Murai 5735d9e6103SBrian Somers extern struct mbuf * 5745d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 575af57ed9fSAtsushi Murai { 5767308ec68SBrian Somers /* Got PROTO_CCP from link */ 57726af0ae9SBrian Somers m_settype(bp, MB_CCPIN); 578455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 5795d9e6103SBrian Somers fsm_Input(&l->ccp.fsm, bp); 580af57ed9fSAtsushi Murai else { 581641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 582dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 5835d9e6103SBrian Somers l->ccp.fsm.link->name, bundle_PhaseName(bundle)); 58426af0ae9SBrian Somers m_freem(bp); 585af57ed9fSAtsushi Murai } 5865d9e6103SBrian Somers return NULL; 587af57ed9fSAtsushi Murai } 5880053cc58SBrian Somers 589503a7782SBrian Somers static void 590503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 5910053cc58SBrian Somers { 5927308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 593f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 594f4768038SBrian Somers 595f4768038SBrian Somers if (ccp->reset_sent != -1) { 596f4768038SBrian Somers if (id != ccp->reset_sent) { 597a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)" 598d47dceb8SBrian Somers " ignored\n", fp->link->name, id, ccp->reset_sent); 59998baf7c8SBrian Somers return; 60098baf7c8SBrian Somers } 60198baf7c8SBrian Somers /* Whaddaya know - a correct reset ack */ 602f4768038SBrian Somers } else if (id == ccp->last_reset) 603dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 604d47dceb8SBrian Somers fp->link->name); 60598baf7c8SBrian Somers else { 606a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n", 607d47dceb8SBrian Somers fp->link->name, id); 60898baf7c8SBrian Somers return; 60998baf7c8SBrian Somers } 61098baf7c8SBrian Somers 611f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 612f4768038SBrian Somers ccp->reset_sent = -1; 61303036ec7SBrian Somers if (ccp->in.state != NULL) 61403036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 6150053cc58SBrian Somers } 6160053cc58SBrian Somers 6175d9e6103SBrian Somers static struct mbuf * 6185d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, 6195d9e6103SBrian Somers int pri, u_short *proto) 6200053cc58SBrian Somers { 6215d9e6103SBrian Somers if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED && 622411675baSBrian Somers l->ccp.out.state != NULL) { 623411675baSBrian Somers bp = (*algorithm[l->ccp.out.algorithm]->o.Write) 6245d9e6103SBrian Somers (l->ccp.out.state, &l->ccp, l, pri, proto, bp); 625411675baSBrian Somers switch (*proto) { 626411675baSBrian Somers case PROTO_ICOMPD: 62726af0ae9SBrian Somers m_settype(bp, MB_ICOMPDOUT); 628411675baSBrian Somers break; 629411675baSBrian Somers case PROTO_COMPD: 63026af0ae9SBrian Somers m_settype(bp, MB_COMPDOUT); 631411675baSBrian Somers break; 632411675baSBrian Somers } 633411675baSBrian Somers } 6345d9e6103SBrian Somers 6355d9e6103SBrian Somers return bp; 6360053cc58SBrian Somers } 6370053cc58SBrian Somers 6385d9e6103SBrian Somers static struct mbuf * 6395d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) 6400053cc58SBrian Somers { 641ee6c193fSBrian Somers /* 642ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 643ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 644ee6c193fSBrian Somers */ 6455d9e6103SBrian Somers if (l->ccp.fsm.state == ST_OPENED) { 646ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 6476815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n", 6486815097bSBrian Somers *proto == PROTO_ICOMPD ? "I" : ""); 6497308ec68SBrian Somers /* Decompress incoming data */ 6505d9e6103SBrian Somers if (l->ccp.reset_sent != -1) 65198baf7c8SBrian Somers /* Send another REQ and put the packet in the bit bucket */ 652411675baSBrian Somers fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0, 653411675baSBrian Somers MB_CCPOUT); 654411675baSBrian Somers else if (l->ccp.in.state != NULL) { 655411675baSBrian Somers bp = (*algorithm[l->ccp.in.algorithm]->i.Read) 6565d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, proto, bp); 657411675baSBrian Somers switch (*proto) { 658411675baSBrian Somers case PROTO_ICOMPD: 65926af0ae9SBrian Somers m_settype(bp, MB_ICOMPDIN); 660411675baSBrian Somers break; 661411675baSBrian Somers case PROTO_COMPD: 66226af0ae9SBrian Somers m_settype(bp, MB_COMPDIN); 663411675baSBrian Somers break; 664411675baSBrian Somers } 665411675baSBrian Somers return bp; 666411675baSBrian Somers } 66726af0ae9SBrian Somers m_freem(bp); 668ee6c193fSBrian Somers bp = NULL; 6696815097bSBrian Somers } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) { 6706815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n"); 671ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 6725d9e6103SBrian Somers (*algorithm[l->ccp.in.algorithm]->i.DictSetup) 6735d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, *proto, bp); 6746815097bSBrian Somers } else 6756815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n"); 6760053cc58SBrian Somers } 6770053cc58SBrian Somers 678ee6c193fSBrian Somers return bp; 6791ae349f5Scvs2svn } 680ed32233cSBrian Somers 681ed32233cSBrian Somers u_short 682ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 6830053cc58SBrian Somers { 684ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 685ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 6860053cc58SBrian Somers } 6871df0a3b9SBrian Somers 68806337856SBrian Somers int 6891df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp) 6901df0a3b9SBrian Somers { 6911df0a3b9SBrian Somers int f; 6921df0a3b9SBrian Somers 6931df0a3b9SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 69406337856SBrian Somers if (IsEnabled(ccp->cfg.neg[f])) { 6951df0a3b9SBrian Somers ccp->fsm.open_mode = 0; 69606337856SBrian Somers return 1; 69706337856SBrian Somers } 6981df0a3b9SBrian Somers 69906337856SBrian Somers ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ 70006337856SBrian Somers 70106337856SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 70206337856SBrian Somers if (IsAccepted(ccp->cfg.neg[f])) 70306337856SBrian Somers return 1; 70406337856SBrian Somers 70506337856SBrian Somers return 0; /* No CCP at all */ 7061df0a3b9SBrian Somers } 7075d9e6103SBrian Somers 7087f89db65SBrian Somers int 7097f89db65SBrian Somers ccp_IsUsable(struct fsm *fp) 7107f89db65SBrian Somers { 7117f89db65SBrian Somers return 1; 7127f89db65SBrian Somers } 7137f89db65SBrian Somers 7145d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull }; 715