1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * PPP Compression Control Protocol (CCP) Module 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Redistribution and use in source and binary forms are permitted 9af57ed9fSAtsushi Murai * provided that the above copyright notice and this paragraph are 10af57ed9fSAtsushi Murai * duplicated in all such forms and that any documentation, 11af57ed9fSAtsushi Murai * advertising materials, and other materials related to such 12af57ed9fSAtsushi Murai * distribution and use acknowledge that the software was developed 13af57ed9fSAtsushi Murai * by the Internet Initiative Japan, Inc. The name of the 14af57ed9fSAtsushi Murai * IIJ may not be used to endorse or promote products derived 15af57ed9fSAtsushi Murai * from this software without specific prior written permission. 16af57ed9fSAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17af57ed9fSAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18af57ed9fSAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19af57ed9fSAtsushi Murai * 20972a1bcfSBrian Somers * $Id: ccp.c,v 1.40 1998/08/26 18:07:56 brian Exp $ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai * o Support other compression protocols 24af57ed9fSAtsushi Murai */ 25972a1bcfSBrian Somers #include <sys/param.h> 2675240ed1SBrian Somers #include <netinet/in.h> 27eaa4df37SBrian Somers #include <netinet/in_systm.h> 28eaa4df37SBrian Somers #include <netinet/ip.h> 291fa665f5SBrian Somers #include <sys/un.h> 3075240ed1SBrian Somers 3175240ed1SBrian Somers #include <stdio.h> 3203036ec7SBrian Somers #include <stdlib.h> 3337d818fbSBrian Somers #include <string.h> 3485b542cfSBrian Somers #include <termios.h> 3575240ed1SBrian Somers 36c9e11a11SBrian Somers #include "defs.h" 37b6e82f33SBrian Somers #include "command.h" 3875240ed1SBrian Somers #include "mbuf.h" 3975240ed1SBrian Somers #include "log.h" 4075240ed1SBrian Somers #include "timer.h" 41af57ed9fSAtsushi Murai #include "fsm.h" 42af57ed9fSAtsushi Murai #include "lcpproto.h" 43af57ed9fSAtsushi Murai #include "lcp.h" 44af57ed9fSAtsushi Murai #include "ccp.h" 45ed6a16c1SPoul-Henning Kamp #include "pred.h" 460053cc58SBrian Somers #include "deflate.h" 475828db6dSBrian Somers #include "throughput.h" 485828db6dSBrian Somers #include "iplist.h" 49eaa4df37SBrian Somers #include "slcompress.h" 505a72b6edSBrian Somers #include "lqr.h" 515a72b6edSBrian Somers #include "hdlc.h" 525828db6dSBrian Somers #include "ipcp.h" 535ca5389aSBrian Somers #include "filter.h" 5485b542cfSBrian Somers #include "descriptor.h" 5585b542cfSBrian Somers #include "prompt.h" 56503a7782SBrian Somers #include "link.h" 573b0f8d2eSBrian Somers #include "mp.h" 58ed32233cSBrian Somers #include "async.h" 59ed32233cSBrian Somers #include "physical.h" 60972a1bcfSBrian Somers #ifndef NORADIUS 61972a1bcfSBrian Somers #include "radius.h" 62972a1bcfSBrian Somers #endif 633b0f8d2eSBrian Somers #include "bundle.h" 64af57ed9fSAtsushi Murai 65927145beSBrian Somers static void CcpSendConfigReq(struct fsm *); 662267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *); 672267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char); 6830c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int, 6930c2f2ffSBrian Somers struct fsm_decode *); 70927145beSBrian Somers static void CcpLayerStart(struct fsm *); 71927145beSBrian Somers static void CcpLayerFinish(struct fsm *); 726f384573SBrian Somers static int CcpLayerUp(struct fsm *); 73927145beSBrian Somers static void CcpLayerDown(struct fsm *); 74927145beSBrian Somers static void CcpInitRestartCounter(struct fsm *); 75503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *); 76503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char); 77af57ed9fSAtsushi Murai 7883d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = { 79af57ed9fSAtsushi Murai CcpLayerUp, 80af57ed9fSAtsushi Murai CcpLayerDown, 81af57ed9fSAtsushi Murai CcpLayerStart, 82af57ed9fSAtsushi Murai CcpLayerFinish, 83af57ed9fSAtsushi Murai CcpInitRestartCounter, 84af57ed9fSAtsushi Murai CcpSendConfigReq, 852267893fSBrian Somers CcpSentTerminateReq, 86af57ed9fSAtsushi Murai CcpSendTerminateAck, 87af57ed9fSAtsushi Murai CcpDecodeConfig, 88503a7782SBrian Somers CcpRecvResetReq, 89503a7782SBrian Somers CcpRecvResetAck 90af57ed9fSAtsushi Murai }; 91af57ed9fSAtsushi Murai 926f384573SBrian Somers static const char *ccp_TimerNames[] = 936f384573SBrian Somers {"CCP restart", "CCP openmode", "CCP stopped"}; 946f384573SBrian Somers 95e53374eaSPoul-Henning Kamp static char const *cftypes[] = { 969e836af5SBrian Somers /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 979e836af5SBrian Somers "OUI", /* 0: OUI */ 989e836af5SBrian Somers "PRED1", /* 1: Predictor type 1 */ 999e836af5SBrian Somers "PRED2", /* 2: Predictor type 2 */ 1009e836af5SBrian Somers "PUDDLE", /* 3: Puddle Jumber */ 1019e836af5SBrian Somers "???", "???", "???", "???", "???", "???", 1029e836af5SBrian Somers "???", "???", "???", "???", "???", "???", 1039e836af5SBrian Somers "HWPPC", /* 16: Hewlett-Packard PPC */ 1044bc84b8cSBrian Somers "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 1058f2e5827SBrian Somers "MPPC", /* 18: Microsoft PPC (rfc2118) */ 1064bc84b8cSBrian Somers "GAND", /* 19: Gandalf FZA (rfc1993) */ 107b6e82f33SBrian Somers "V42BIS", /* 20: ARG->DATA.42bis compression */ 1080053cc58SBrian Somers "BSD", /* 21: BSD LZW Compress */ 1090053cc58SBrian Somers "???", 1104bc84b8cSBrian Somers "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 1114bc84b8cSBrian Somers "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 1121342caedSBrian Somers /* 24: Deflate (according to pppd-2.3.*) */ 1134bc84b8cSBrian Somers "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 1144bc84b8cSBrian Somers "DEFLATE", /* 26: Deflate (rfc1979) */ 115af57ed9fSAtsushi Murai }; 116af57ed9fSAtsushi Murai 11770ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 1189e836af5SBrian Somers 1190053cc58SBrian Somers static const char * 1200053cc58SBrian Somers protoname(int proto) 1210053cc58SBrian Somers { 1220053cc58SBrian Somers if (proto < 0 || proto > NCFTYPES) 1230053cc58SBrian Somers return "none"; 1240053cc58SBrian Somers return cftypes[proto]; 1250053cc58SBrian Somers } 1260053cc58SBrian Somers 1274bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */ 1280053cc58SBrian Somers static const struct ccp_algorithm *algorithm[] = { 1294bc84b8cSBrian Somers &DeflateAlgorithm, 1300053cc58SBrian Somers &Pred1Algorithm, 1314bc84b8cSBrian Somers &PppdDeflateAlgorithm 1320053cc58SBrian Somers }; 1330053cc58SBrian Somers 13470ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 1350053cc58SBrian Somers 136274e766cSBrian Somers int 137503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg) 138af57ed9fSAtsushi Murai { 139dd0645c5SBrian Somers struct link *l; 140dd0645c5SBrian Somers struct ccp *ccp; 141dd0645c5SBrian Somers 1423a2e4f62SBrian Somers l = command_ChooseLink(arg); 143dd0645c5SBrian Somers ccp = &l->ccp; 144503a7782SBrian Somers 145b6217683SBrian Somers prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, 1461e991daaSBrian Somers State2Nam(ccp->fsm.state)); 147b6217683SBrian Somers prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", 148503a7782SBrian Somers protoname(ccp->my_proto), protoname(ccp->his_proto)); 149b6217683SBrian Somers prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", 150503a7782SBrian Somers ccp->uncompout, ccp->compout, 151503a7782SBrian Somers ccp->compin, ccp->uncompin); 152cd9647a1SBrian Somers 153b6217683SBrian Somers prompt_Printf(arg->prompt, "\n Defaults: "); 1541342caedSBrian Somers prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry); 155b6217683SBrian Somers prompt_Printf(arg->prompt, " deflate windows: "); 156b6217683SBrian Somers prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); 157b6217683SBrian Somers prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); 1581342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE: %s\n", 1591342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); 1601342caedSBrian Somers prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", 1611342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); 1621342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE24: %s\n", 1631342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); 164274e766cSBrian Somers return 0; 165af57ed9fSAtsushi Murai } 166af57ed9fSAtsushi Murai 1671ae349f5Scvs2svn void 1686f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp) 169af57ed9fSAtsushi Murai { 1706f384573SBrian Somers ccp->fsm.fn = &ccp_Callbacks; 1716f384573SBrian Somers ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; 1726f384573SBrian Somers ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; 1736f384573SBrian Somers ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; 174ea661041SBrian Somers } 175ea661041SBrian Somers 176ea661041SBrian Somers void 1776d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, 1786d666775SBrian Somers const struct fsm_parent *parent) 179ea661041SBrian Somers { 1807308ec68SBrian Somers /* Initialise ourselves */ 1813b0f8d2eSBrian Somers 1823b0f8d2eSBrian Somers fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP, 1836f384573SBrian Somers bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); 184cd9647a1SBrian Somers 18503036ec7SBrian Somers ccp->cfg.deflate.in.winsize = 0; 18603036ec7SBrian Somers ccp->cfg.deflate.out.winsize = 15; 187cd9647a1SBrian Somers ccp->cfg.fsmretry = DEF_FSMRETRY; 1881342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; 1891342caedSBrian Somers ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; 1901342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; 191cd9647a1SBrian Somers 192503a7782SBrian Somers ccp_Setup(ccp); 193503a7782SBrian Somers } 194503a7782SBrian Somers 195503a7782SBrian Somers void 196503a7782SBrian Somers ccp_Setup(struct ccp *ccp) 197503a7782SBrian Somers { 198503a7782SBrian Somers /* Set ourselves up for a startup */ 199503a7782SBrian Somers ccp->fsm.open_mode = 0; 2005454ccd9SBrian Somers ccp->fsm.maxconfig = 10; 201503a7782SBrian Somers ccp->his_proto = ccp->my_proto = -1; 202503a7782SBrian Somers ccp->reset_sent = ccp->last_reset = -1; 20303036ec7SBrian Somers ccp->in.algorithm = ccp->out.algorithm = -1; 20403036ec7SBrian Somers ccp->in.state = ccp->out.state = NULL; 20503036ec7SBrian Somers ccp->in.opt.id = -1; 20603036ec7SBrian Somers ccp->out.opt = NULL; 207503a7782SBrian Somers ccp->his_reject = ccp->my_reject = 0; 208503a7782SBrian Somers ccp->uncompout = ccp->compout = 0; 209503a7782SBrian Somers ccp->uncompin = ccp->compin = 0; 210af57ed9fSAtsushi Murai } 211af57ed9fSAtsushi Murai 212af57ed9fSAtsushi Murai static void 213944f7098SBrian Somers CcpInitRestartCounter(struct fsm *fp) 214af57ed9fSAtsushi Murai { 2157308ec68SBrian Somers /* Set fsm timer load */ 216cd9647a1SBrian Somers struct ccp *ccp = fsm2ccp(fp); 217cd9647a1SBrian Somers 218cd9647a1SBrian Somers fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS; 21992b09558SBrian Somers fp->restart = DEF_REQs; 220af57ed9fSAtsushi Murai } 221af57ed9fSAtsushi Murai 222af57ed9fSAtsushi Murai static void 223944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp) 224af57ed9fSAtsushi Murai { 2257308ec68SBrian Somers /* Send config REQ please */ 226aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 22703036ec7SBrian Somers struct ccp_opt **o; 22830c2f2ffSBrian Somers u_char *cp, buff[100]; 22903036ec7SBrian Somers int f, alloc; 230af57ed9fSAtsushi Murai 23130c2f2ffSBrian Somers cp = buff; 23203036ec7SBrian Somers o = &ccp->out.opt; 23303036ec7SBrian Somers alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; 23483d1af55SBrian Somers ccp->my_proto = -1; 23503036ec7SBrian Somers ccp->out.algorithm = -1; 2360053cc58SBrian Somers for (f = 0; f < NALGORITHMS; f++) 2371342caedSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && 2381342caedSBrian Somers !REJECTED(ccp, algorithm[f]->id)) { 2390053cc58SBrian Somers 240ba081e43SBrian Somers if (!alloc) 241ba081e43SBrian Somers for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) 242ba081e43SBrian Somers if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) 243ba081e43SBrian Somers break; 244ba081e43SBrian Somers 245ba081e43SBrian Somers if (alloc || *o == NULL) { 24603036ec7SBrian Somers *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); 24703036ec7SBrian Somers (*o)->val.id = algorithm[f]->id; 24803036ec7SBrian Somers (*o)->val.len = 2; 24903036ec7SBrian Somers (*o)->next = NULL; 25003036ec7SBrian Somers (*o)->algorithm = f; 25103036ec7SBrian Somers (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); 252af57ed9fSAtsushi Murai } 2531ae349f5Scvs2svn 25403036ec7SBrian Somers if (cp + (*o)->val.len > buff + sizeof buff) { 255dd7e2610SBrian Somers log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); 25630c2f2ffSBrian Somers break; 25730c2f2ffSBrian Somers } 2582267893fSBrian Somers memcpy(cp, &(*o)->val, (*o)->val.len); 2592267893fSBrian Somers cp += (*o)->val.len; 26003036ec7SBrian Somers 26103036ec7SBrian Somers ccp->my_proto = (*o)->val.id; 26203036ec7SBrian Somers ccp->out.algorithm = f; 26303036ec7SBrian Somers 26403036ec7SBrian Somers if (alloc) 26503036ec7SBrian Somers o = &(*o)->next; 2661ae349f5Scvs2svn } 2672267893fSBrian Somers 268dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff); 269af57ed9fSAtsushi Murai } 270af57ed9fSAtsushi Murai 271af57ed9fSAtsushi Murai void 272dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp) 273af57ed9fSAtsushi Murai { 2747308ec68SBrian Somers /* We can't read our input - ask peer to reset */ 275aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 2762267893fSBrian Somers 27783d1af55SBrian Somers ccp->reset_sent = fp->reqid; 27883d1af55SBrian Somers ccp->last_reset = -1; 279dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0); 280af57ed9fSAtsushi Murai } 281af57ed9fSAtsushi Murai 282af57ed9fSAtsushi Murai static void 2832267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp) 284af57ed9fSAtsushi Murai { 2857308ec68SBrian Somers /* Term REQ just sent by FSM */ 286af57ed9fSAtsushi Murai } 287af57ed9fSAtsushi Murai 288af57ed9fSAtsushi Murai static void 2892267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id) 290af57ed9fSAtsushi Murai { 2917308ec68SBrian Somers /* Send Term ACK please */ 292dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 293af57ed9fSAtsushi Murai } 294af57ed9fSAtsushi Murai 295503a7782SBrian Somers static void 296944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp) 297af57ed9fSAtsushi Murai { 2987308ec68SBrian Somers /* Got a reset REQ, reset outgoing dictionary */ 299aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 30003036ec7SBrian Somers if (ccp->out.state != NULL) 30103036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); 302af57ed9fSAtsushi Murai } 303af57ed9fSAtsushi Murai 304af57ed9fSAtsushi Murai static void 305944f7098SBrian Somers CcpLayerStart(struct fsm *fp) 306af57ed9fSAtsushi Murai { 3077308ec68SBrian Somers /* We're about to start up ! */ 3083a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); 309af57ed9fSAtsushi Murai } 310af57ed9fSAtsushi Murai 311af57ed9fSAtsushi Murai static void 312897f9429SBrian Somers CcpLayerDown(struct fsm *fp) 313af57ed9fSAtsushi Murai { 314897f9429SBrian Somers /* About to come down */ 315aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 316ba081e43SBrian Somers struct ccp_opt *next; 317ba081e43SBrian Somers 3183a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); 31903036ec7SBrian Somers if (ccp->in.state != NULL) { 32003036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); 32103036ec7SBrian Somers ccp->in.state = NULL; 3228d9b9867SBrian Somers ccp->in.algorithm = -1; 3237308ec68SBrian Somers } 32403036ec7SBrian Somers if (ccp->out.state != NULL) { 32503036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); 32603036ec7SBrian Somers ccp->out.state = NULL; 3278d9b9867SBrian Somers ccp->out.algorithm = -1; 3287308ec68SBrian Somers } 3298d9b9867SBrian Somers ccp->his_reject = ccp->my_reject = 0; 330ba081e43SBrian Somers 331ba081e43SBrian Somers while (ccp->out.opt) { 332ba081e43SBrian Somers next = ccp->out.opt->next; 333ba081e43SBrian Somers free(ccp->out.opt); 334ba081e43SBrian Somers ccp->out.opt = next; 335ba081e43SBrian Somers } 336897f9429SBrian Somers ccp_Setup(ccp); 337af57ed9fSAtsushi Murai } 338af57ed9fSAtsushi Murai 339af57ed9fSAtsushi Murai static void 340897f9429SBrian Somers CcpLayerFinish(struct fsm *fp) 341af57ed9fSAtsushi Murai { 342897f9429SBrian Somers /* We're now down */ 3433a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); 344af57ed9fSAtsushi Murai } 345af57ed9fSAtsushi Murai 346af57ed9fSAtsushi Murai /* 3470053cc58SBrian Somers * Called when CCP has reached the OPEN state 348af57ed9fSAtsushi Murai */ 3496f384573SBrian Somers static int 350944f7098SBrian Somers CcpLayerUp(struct fsm *fp) 351af57ed9fSAtsushi Murai { 3527308ec68SBrian Somers /* We're now up */ 353aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 3543a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); 35503036ec7SBrian Somers if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 35603036ec7SBrian Somers ccp->in.algorithm < NALGORITHMS) { 35703036ec7SBrian Somers ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 35803036ec7SBrian Somers if (ccp->in.state == NULL) { 359dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", 360d47dceb8SBrian Somers fp->link->name, protoname(ccp->his_proto)); 36183d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 362dd7e2610SBrian Somers fsm_Close(fp); 36379d1bdaeSBrian Somers } 364af57ed9fSAtsushi Murai } 365af57ed9fSAtsushi Murai 36603036ec7SBrian Somers if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 36703036ec7SBrian Somers ccp->out.algorithm < NALGORITHMS) { 36803036ec7SBrian Somers ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) 36903036ec7SBrian Somers (&ccp->out.opt->val); 37003036ec7SBrian Somers if (ccp->out.state == NULL) { 371dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", 372d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto)); 37383d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 374dd7e2610SBrian Somers fsm_Close(fp); 375247ab36dSBrian Somers } 376af57ed9fSAtsushi Murai } 377af57ed9fSAtsushi Murai 378dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 379d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 38083d1af55SBrian Somers protoname(ccp->his_proto), ccp->his_proto); 3816f384573SBrian Somers return 1; 382af57ed9fSAtsushi Murai } 383af57ed9fSAtsushi Murai 384af57ed9fSAtsushi Murai static void 38530c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 38630c2f2ffSBrian Somers struct fsm_decode *dec) 387af57ed9fSAtsushi Murai { 3887308ec68SBrian Somers /* Deal with incoming data */ 389aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 39053c9f6c0SAtsushi Murai int type, length; 3910053cc58SBrian Somers int f; 39203036ec7SBrian Somers const char *end; 393af57ed9fSAtsushi Murai 394af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 395af57ed9fSAtsushi Murai type = *cp; 396af57ed9fSAtsushi Murai length = cp[1]; 39703036ec7SBrian Somers 398d47dceb8SBrian Somers if (length == 0) { 399dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); 400d47dceb8SBrian Somers break; 401d47dceb8SBrian Somers } 402d47dceb8SBrian Somers 40303036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 40403036ec7SBrian Somers length = sizeof(struct lcp_opt); 405dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", 406d47dceb8SBrian Somers fp->link->name, length); 40703036ec7SBrian Somers } 408af57ed9fSAtsushi Murai 4090053cc58SBrian Somers for (f = NALGORITHMS-1; f > -1; f--) 4100053cc58SBrian Somers if (algorithm[f]->id == type) 4110053cc58SBrian Somers break; 412af57ed9fSAtsushi Murai 41303036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 41403036ec7SBrian Somers if (end == NULL) 41503036ec7SBrian Somers end = ""; 41603036ec7SBrian Somers 41703036ec7SBrian Somers if (type < NCFTYPES) 418dd7e2610SBrian Somers log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); 41903036ec7SBrian Somers else 420dd7e2610SBrian Somers log_Printf(LogCCP, " ???[%d] %s\n", length, end); 42103036ec7SBrian Somers 4220053cc58SBrian Somers if (f == -1) { 4230053cc58SBrian Somers /* Don't understand that :-( */ 4240053cc58SBrian Somers if (mode_type == MODE_REQ) { 42583d1af55SBrian Somers ccp->my_reject |= (1 << type); 42630c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 42730c2f2ffSBrian Somers dec->rejend += length; 4280053cc58SBrian Somers } 4290053cc58SBrian Somers } else { 43003036ec7SBrian Somers struct ccp_opt *o; 4310053cc58SBrian Somers 4329780ef31SBrian Somers switch (mode_type) { 433af57ed9fSAtsushi Murai case MODE_REQ: 4341342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 4351342caedSBrian Somers ccp->in.algorithm == -1) { 43603036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 43703036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 4380053cc58SBrian Somers case MODE_REJ: 43903036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 44003036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 4410053cc58SBrian Somers break; 4420053cc58SBrian Somers case MODE_NAK: 44303036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 44403036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 4450053cc58SBrian Somers break; 4460053cc58SBrian Somers case MODE_ACK: 44730c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 44830c2f2ffSBrian Somers dec->ackend += length; 44983d1af55SBrian Somers ccp->his_proto = type; 45003036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 4510053cc58SBrian Somers break; 4520053cc58SBrian Somers } 453af57ed9fSAtsushi Murai } else { 45430c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 45530c2f2ffSBrian Somers dec->rejend += length; 456af57ed9fSAtsushi Murai } 457af57ed9fSAtsushi Murai break; 458af57ed9fSAtsushi Murai case MODE_NAK: 45903036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 46003036ec7SBrian Somers if (o->val.id == cp[0]) 46103036ec7SBrian Somers break; 46203036ec7SBrian Somers if (o == NULL) 463dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n", 464d47dceb8SBrian Somers fp->link->name); 4650053cc58SBrian Somers else { 46603036ec7SBrian Somers memcpy(&o->val, cp, length); 46703036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 46883d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 4691ae349f5Scvs2svn else { 47083d1af55SBrian Somers ccp->his_reject |= (1 << type); 47183d1af55SBrian Somers ccp->my_proto = -1; 4721ae349f5Scvs2svn } 4730053cc58SBrian Somers } 4740053cc58SBrian Somers break; 475af57ed9fSAtsushi Murai case MODE_REJ: 47683d1af55SBrian Somers ccp->his_reject |= (1 << type); 47783d1af55SBrian Somers ccp->my_proto = -1; 478af57ed9fSAtsushi Murai break; 479af57ed9fSAtsushi Murai } 480af57ed9fSAtsushi Murai } 4810053cc58SBrian Somers 48203036ec7SBrian Somers plen -= cp[1]; 48303036ec7SBrian Somers cp += cp[1]; 484af57ed9fSAtsushi Murai } 4850053cc58SBrian Somers 486e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 4871342caedSBrian Somers if (dec->rejend != dec->rej) { 48803036ec7SBrian Somers /* rejects are preferred */ 48903036ec7SBrian Somers dec->ackend = dec->ack; 49003036ec7SBrian Somers dec->nakend = dec->nak; 49103036ec7SBrian Somers if (ccp->in.state == NULL) { 49283d1af55SBrian Somers ccp->his_proto = -1; 49303036ec7SBrian Somers ccp->in.algorithm = -1; 49403036ec7SBrian Somers } 4951342caedSBrian Somers } else if (dec->nakend != dec->nak) { 49603036ec7SBrian Somers /* then NAKs */ 49703036ec7SBrian Somers dec->ackend = dec->ack; 49803036ec7SBrian Somers if (ccp->in.state == NULL) { 49903036ec7SBrian Somers ccp->his_proto = -1; 50003036ec7SBrian Somers ccp->in.algorithm = -1; 501247ab36dSBrian Somers } 5021ae349f5Scvs2svn } 5030053cc58SBrian Somers } 504af57ed9fSAtsushi Murai } 505af57ed9fSAtsushi Murai 506af57ed9fSAtsushi Murai void 507dd7e2610SBrian Somers ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) 508af57ed9fSAtsushi Murai { 5097308ec68SBrian Somers /* Got PROTO_CCP from link */ 510455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 511dd7e2610SBrian Somers fsm_Input(&ccp->fsm, bp); 512af57ed9fSAtsushi Murai else { 513641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 514dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 515d47dceb8SBrian Somers ccp->fsm.link->name, bundle_PhaseName(bundle)); 516dd7e2610SBrian Somers mbuf_Free(bp); 517af57ed9fSAtsushi Murai } 518af57ed9fSAtsushi Murai } 5190053cc58SBrian Somers 520503a7782SBrian Somers static void 521503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 5220053cc58SBrian Somers { 5237308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 524f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 525f4768038SBrian Somers 526f4768038SBrian Somers if (ccp->reset_sent != -1) { 527f4768038SBrian Somers if (id != ccp->reset_sent) { 528dd7e2610SBrian Somers log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)" 529d47dceb8SBrian Somers " ignored\n", fp->link->name, id, ccp->reset_sent); 53098baf7c8SBrian Somers return; 53198baf7c8SBrian Somers } 53298baf7c8SBrian Somers /* Whaddaya know - a correct reset ack */ 533f4768038SBrian Somers } else if (id == ccp->last_reset) 534dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 535d47dceb8SBrian Somers fp->link->name); 53698baf7c8SBrian Somers else { 537dd7e2610SBrian Somers log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n", 538d47dceb8SBrian Somers fp->link->name, id); 53998baf7c8SBrian Somers return; 54098baf7c8SBrian Somers } 54198baf7c8SBrian Somers 542f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 543f4768038SBrian Somers ccp->reset_sent = -1; 54403036ec7SBrian Somers if (ccp->in.state != NULL) 54503036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 5460053cc58SBrian Somers } 5470053cc58SBrian Somers 5480053cc58SBrian Somers int 5493b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto, 550503a7782SBrian Somers struct mbuf *m) 5510053cc58SBrian Somers { 5520a1b5c9dSBrian Somers /* 5530a1b5c9dSBrian Somers * Compress outgoing data. It's already deemed to be suitable Network 5540a1b5c9dSBrian Somers * Layer data. 5550a1b5c9dSBrian Somers */ 5560a1b5c9dSBrian Somers if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL) 55703036ec7SBrian Somers return (*algorithm[ccp->out.algorithm]->o.Write) 55803036ec7SBrian Somers (ccp->out.state, ccp, l, pri, proto, m); 5590053cc58SBrian Somers return 0; 5600053cc58SBrian Somers } 5610053cc58SBrian Somers 5620053cc58SBrian Somers struct mbuf * 563503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) 5640053cc58SBrian Somers { 565ee6c193fSBrian Somers /* 566ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 567ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 568ee6c193fSBrian Somers */ 569e43ebac1SBrian Somers if (ccp->fsm.state == ST_OPENED) { 570ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 5717308ec68SBrian Somers /* Decompress incoming data */ 5722267893fSBrian Somers if (ccp->reset_sent != -1) 57398baf7c8SBrian Somers /* Send another REQ and put the packet in the bit bucket */ 574dd7e2610SBrian Somers fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); 5752267893fSBrian Somers else if (ccp->in.state != NULL) 57603036ec7SBrian Somers return (*algorithm[ccp->in.algorithm]->i.Read) 57703036ec7SBrian Somers (ccp->in.state, ccp, proto, bp); 578dd7e2610SBrian Somers mbuf_Free(bp); 579ee6c193fSBrian Somers bp = NULL; 5800a1b5c9dSBrian Somers } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL) 581ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 58203036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.DictSetup) 58303036ec7SBrian Somers (ccp->in.state, ccp, *proto, bp); 5840053cc58SBrian Somers } 5850053cc58SBrian Somers 586ee6c193fSBrian Somers return bp; 5871ae349f5Scvs2svn } 588ed32233cSBrian Somers 589ed32233cSBrian Somers u_short 590ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 5910053cc58SBrian Somers { 592ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 593ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 5940053cc58SBrian Somers } 5951df0a3b9SBrian Somers 59606337856SBrian Somers int 5971df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp) 5981df0a3b9SBrian Somers { 5991df0a3b9SBrian Somers int f; 6001df0a3b9SBrian Somers 6011df0a3b9SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 60206337856SBrian Somers if (IsEnabled(ccp->cfg.neg[f])) { 6031df0a3b9SBrian Somers ccp->fsm.open_mode = 0; 60406337856SBrian Somers return 1; 60506337856SBrian Somers } 6061df0a3b9SBrian Somers 60706337856SBrian Somers ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ 60806337856SBrian Somers 60906337856SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 61006337856SBrian Somers if (IsAccepted(ccp->cfg.neg[f])) 61106337856SBrian Somers return 1; 61206337856SBrian Somers 61306337856SBrian Somers return 0; /* No CCP at all */ 6141df0a3b9SBrian Somers } 615