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 * 20897f9429SBrian Somers * $Id: ccp.c,v 1.34 1998/06/15 19:06:02 brian Exp $ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai * o Support other compression protocols 24af57ed9fSAtsushi Murai */ 252764b86aSBrian Somers #include <sys/types.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> 3385b542cfSBrian Somers #include <termios.h> 3475240ed1SBrian Somers 35c9e11a11SBrian Somers #include "defs.h" 36b6e82f33SBrian Somers #include "command.h" 3775240ed1SBrian Somers #include "mbuf.h" 3875240ed1SBrian Somers #include "log.h" 3975240ed1SBrian Somers #include "timer.h" 40af57ed9fSAtsushi Murai #include "fsm.h" 41af57ed9fSAtsushi Murai #include "lcpproto.h" 42af57ed9fSAtsushi Murai #include "lcp.h" 43af57ed9fSAtsushi Murai #include "ccp.h" 44ed6a16c1SPoul-Henning Kamp #include "pred.h" 450053cc58SBrian Somers #include "deflate.h" 465828db6dSBrian Somers #include "throughput.h" 475828db6dSBrian Somers #include "iplist.h" 48eaa4df37SBrian Somers #include "slcompress.h" 495828db6dSBrian Somers #include "ipcp.h" 505ca5389aSBrian Somers #include "filter.h" 5185b542cfSBrian Somers #include "descriptor.h" 5285b542cfSBrian Somers #include "prompt.h" 53879ed6faSBrian Somers #include "lqr.h" 54503a7782SBrian Somers #include "hdlc.h" 55503a7782SBrian Somers #include "link.h" 563b0f8d2eSBrian Somers #include "mp.h" 57ed32233cSBrian Somers #include "async.h" 58ed32233cSBrian Somers #include "physical.h" 593b0f8d2eSBrian Somers #include "bundle.h" 60af57ed9fSAtsushi Murai 61927145beSBrian Somers static void CcpSendConfigReq(struct fsm *); 622267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *); 632267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char); 6430c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int, 6530c2f2ffSBrian Somers struct fsm_decode *); 66927145beSBrian Somers static void CcpLayerStart(struct fsm *); 67927145beSBrian Somers static void CcpLayerFinish(struct fsm *); 686f384573SBrian Somers static int CcpLayerUp(struct fsm *); 69927145beSBrian Somers static void CcpLayerDown(struct fsm *); 70927145beSBrian Somers static void CcpInitRestartCounter(struct fsm *); 71503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *); 72503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char); 73af57ed9fSAtsushi Murai 7483d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = { 75af57ed9fSAtsushi Murai CcpLayerUp, 76af57ed9fSAtsushi Murai CcpLayerDown, 77af57ed9fSAtsushi Murai CcpLayerStart, 78af57ed9fSAtsushi Murai CcpLayerFinish, 79af57ed9fSAtsushi Murai CcpInitRestartCounter, 80af57ed9fSAtsushi Murai CcpSendConfigReq, 812267893fSBrian Somers CcpSentTerminateReq, 82af57ed9fSAtsushi Murai CcpSendTerminateAck, 83af57ed9fSAtsushi Murai CcpDecodeConfig, 84503a7782SBrian Somers CcpRecvResetReq, 85503a7782SBrian Somers CcpRecvResetAck 86af57ed9fSAtsushi Murai }; 87af57ed9fSAtsushi Murai 886f384573SBrian Somers static const char *ccp_TimerNames[] = 896f384573SBrian Somers {"CCP restart", "CCP openmode", "CCP stopped"}; 906f384573SBrian Somers 91e53374eaSPoul-Henning Kamp static char const *cftypes[] = { 929e836af5SBrian Somers /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 939e836af5SBrian Somers "OUI", /* 0: OUI */ 949e836af5SBrian Somers "PRED1", /* 1: Predictor type 1 */ 959e836af5SBrian Somers "PRED2", /* 2: Predictor type 2 */ 969e836af5SBrian Somers "PUDDLE", /* 3: Puddle Jumber */ 979e836af5SBrian Somers "???", "???", "???", "???", "???", "???", 989e836af5SBrian Somers "???", "???", "???", "???", "???", "???", 999e836af5SBrian Somers "HWPPC", /* 16: Hewlett-Packard PPC */ 1004bc84b8cSBrian Somers "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 1018f2e5827SBrian Somers "MPPC", /* 18: Microsoft PPC (rfc2118) */ 1024bc84b8cSBrian Somers "GAND", /* 19: Gandalf FZA (rfc1993) */ 103b6e82f33SBrian Somers "V42BIS", /* 20: ARG->DATA.42bis compression */ 1040053cc58SBrian Somers "BSD", /* 21: BSD LZW Compress */ 1050053cc58SBrian Somers "???", 1064bc84b8cSBrian Somers "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 1074bc84b8cSBrian Somers "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 1081342caedSBrian Somers /* 24: Deflate (according to pppd-2.3.*) */ 1094bc84b8cSBrian Somers "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 1104bc84b8cSBrian Somers "DEFLATE", /* 26: Deflate (rfc1979) */ 111af57ed9fSAtsushi Murai }; 112af57ed9fSAtsushi Murai 11370ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 1149e836af5SBrian Somers 1150053cc58SBrian Somers static const char * 1160053cc58SBrian Somers protoname(int proto) 1170053cc58SBrian Somers { 1180053cc58SBrian Somers if (proto < 0 || proto > NCFTYPES) 1190053cc58SBrian Somers return "none"; 1200053cc58SBrian Somers return cftypes[proto]; 1210053cc58SBrian Somers } 1220053cc58SBrian Somers 1234bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */ 1240053cc58SBrian Somers static const struct ccp_algorithm *algorithm[] = { 1254bc84b8cSBrian Somers &DeflateAlgorithm, 1260053cc58SBrian Somers &Pred1Algorithm, 1274bc84b8cSBrian Somers &PppdDeflateAlgorithm 1280053cc58SBrian Somers }; 1290053cc58SBrian Somers 13070ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 1310053cc58SBrian Somers 132274e766cSBrian Somers int 133503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg) 134af57ed9fSAtsushi Murai { 135dd0645c5SBrian Somers struct link *l; 136dd0645c5SBrian Somers struct ccp *ccp; 137dd0645c5SBrian Somers 138dd0645c5SBrian Somers if (!(l = command_ChooseLink(arg))) 139dd0645c5SBrian Somers return -1; 140dd0645c5SBrian Somers ccp = &l->ccp; 141503a7782SBrian Somers 142b6217683SBrian Somers prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, 1431e991daaSBrian Somers State2Nam(ccp->fsm.state)); 144b6217683SBrian Somers prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", 145503a7782SBrian Somers protoname(ccp->my_proto), protoname(ccp->his_proto)); 146b6217683SBrian Somers prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", 147503a7782SBrian Somers ccp->uncompout, ccp->compout, 148503a7782SBrian Somers ccp->compin, ccp->uncompin); 149cd9647a1SBrian Somers 150b6217683SBrian Somers prompt_Printf(arg->prompt, "\n Defaults: "); 1511342caedSBrian Somers prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry); 152b6217683SBrian Somers prompt_Printf(arg->prompt, " deflate windows: "); 153b6217683SBrian Somers prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); 154b6217683SBrian Somers prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); 1551342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE: %s\n", 1561342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); 1571342caedSBrian Somers prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", 1581342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); 1591342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE24: %s\n", 1601342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); 161274e766cSBrian Somers return 0; 162af57ed9fSAtsushi Murai } 163af57ed9fSAtsushi Murai 1641ae349f5Scvs2svn void 1656f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp) 166af57ed9fSAtsushi Murai { 1676f384573SBrian Somers ccp->fsm.fn = &ccp_Callbacks; 1686f384573SBrian Somers ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; 1696f384573SBrian Somers ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; 1706f384573SBrian Somers ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; 171ea661041SBrian Somers } 172ea661041SBrian Somers 173ea661041SBrian Somers void 1746d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, 1756d666775SBrian Somers const struct fsm_parent *parent) 176ea661041SBrian Somers { 1777308ec68SBrian Somers /* Initialise ourselves */ 1783b0f8d2eSBrian Somers 1793b0f8d2eSBrian Somers fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP, 1806f384573SBrian Somers bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); 181cd9647a1SBrian Somers 18203036ec7SBrian Somers ccp->cfg.deflate.in.winsize = 0; 18303036ec7SBrian Somers ccp->cfg.deflate.out.winsize = 15; 184cd9647a1SBrian Somers ccp->cfg.fsmretry = DEF_FSMRETRY; 1851342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; 1861342caedSBrian Somers ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; 1871342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; 188cd9647a1SBrian Somers 189503a7782SBrian Somers ccp_Setup(ccp); 190503a7782SBrian Somers } 191503a7782SBrian Somers 192503a7782SBrian Somers void 193503a7782SBrian Somers ccp_Setup(struct ccp *ccp) 194503a7782SBrian Somers { 195503a7782SBrian Somers /* Set ourselves up for a startup */ 196503a7782SBrian Somers ccp->fsm.open_mode = 0; 1975454ccd9SBrian Somers ccp->fsm.maxconfig = 10; 198503a7782SBrian Somers ccp->his_proto = ccp->my_proto = -1; 199503a7782SBrian Somers ccp->reset_sent = ccp->last_reset = -1; 20003036ec7SBrian Somers ccp->in.algorithm = ccp->out.algorithm = -1; 20103036ec7SBrian Somers ccp->in.state = ccp->out.state = NULL; 20203036ec7SBrian Somers ccp->in.opt.id = -1; 20303036ec7SBrian Somers ccp->out.opt = NULL; 204503a7782SBrian Somers ccp->his_reject = ccp->my_reject = 0; 205503a7782SBrian Somers ccp->uncompout = ccp->compout = 0; 206503a7782SBrian Somers ccp->uncompin = ccp->compin = 0; 207af57ed9fSAtsushi Murai } 208af57ed9fSAtsushi Murai 209af57ed9fSAtsushi Murai static void 210944f7098SBrian Somers CcpInitRestartCounter(struct fsm *fp) 211af57ed9fSAtsushi Murai { 2127308ec68SBrian Somers /* Set fsm timer load */ 213cd9647a1SBrian Somers struct ccp *ccp = fsm2ccp(fp); 214cd9647a1SBrian Somers 215cd9647a1SBrian Somers fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS; 216af57ed9fSAtsushi Murai fp->restart = 5; 217af57ed9fSAtsushi Murai } 218af57ed9fSAtsushi Murai 219af57ed9fSAtsushi Murai static void 220944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp) 221af57ed9fSAtsushi Murai { 2227308ec68SBrian Somers /* Send config REQ please */ 223aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 22403036ec7SBrian Somers struct ccp_opt **o; 22530c2f2ffSBrian Somers u_char *cp, buff[100]; 22603036ec7SBrian Somers int f, alloc; 227af57ed9fSAtsushi Murai 22830c2f2ffSBrian Somers cp = buff; 22903036ec7SBrian Somers o = &ccp->out.opt; 23003036ec7SBrian Somers alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; 23183d1af55SBrian Somers ccp->my_proto = -1; 23203036ec7SBrian Somers ccp->out.algorithm = -1; 2330053cc58SBrian Somers for (f = 0; f < NALGORITHMS; f++) 2341342caedSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && 2351342caedSBrian Somers !REJECTED(ccp, algorithm[f]->id)) { 2360053cc58SBrian Somers 237ba081e43SBrian Somers if (!alloc) 238ba081e43SBrian Somers for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) 239ba081e43SBrian Somers if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) 240ba081e43SBrian Somers break; 241ba081e43SBrian Somers 242ba081e43SBrian Somers if (alloc || *o == NULL) { 24303036ec7SBrian Somers *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); 24403036ec7SBrian Somers (*o)->val.id = algorithm[f]->id; 24503036ec7SBrian Somers (*o)->val.len = 2; 24603036ec7SBrian Somers (*o)->next = NULL; 24703036ec7SBrian Somers (*o)->algorithm = f; 24803036ec7SBrian Somers (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); 249af57ed9fSAtsushi Murai } 2501ae349f5Scvs2svn 25103036ec7SBrian Somers if (cp + (*o)->val.len > buff + sizeof buff) { 252dd7e2610SBrian Somers log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); 25330c2f2ffSBrian Somers break; 25430c2f2ffSBrian Somers } 2552267893fSBrian Somers memcpy(cp, &(*o)->val, (*o)->val.len); 2562267893fSBrian Somers cp += (*o)->val.len; 25703036ec7SBrian Somers 25803036ec7SBrian Somers ccp->my_proto = (*o)->val.id; 25903036ec7SBrian Somers ccp->out.algorithm = f; 26003036ec7SBrian Somers 26103036ec7SBrian Somers if (alloc) 26203036ec7SBrian Somers o = &(*o)->next; 2631ae349f5Scvs2svn } 2642267893fSBrian Somers 265dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff); 266af57ed9fSAtsushi Murai } 267af57ed9fSAtsushi Murai 268af57ed9fSAtsushi Murai void 269dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp) 270af57ed9fSAtsushi Murai { 2717308ec68SBrian Somers /* We can't read our input - ask peer to reset */ 272aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 2732267893fSBrian Somers 27483d1af55SBrian Somers ccp->reset_sent = fp->reqid; 27583d1af55SBrian Somers ccp->last_reset = -1; 276dd7e2610SBrian Somers fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0); 277af57ed9fSAtsushi Murai } 278af57ed9fSAtsushi Murai 279af57ed9fSAtsushi Murai static void 2802267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp) 281af57ed9fSAtsushi Murai { 2827308ec68SBrian Somers /* Term REQ just sent by FSM */ 283af57ed9fSAtsushi Murai } 284af57ed9fSAtsushi Murai 285af57ed9fSAtsushi Murai static void 2862267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id) 287af57ed9fSAtsushi Murai { 2887308ec68SBrian Somers /* Send Term ACK please */ 289dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 290af57ed9fSAtsushi Murai } 291af57ed9fSAtsushi Murai 292503a7782SBrian Somers static void 293944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp) 294af57ed9fSAtsushi Murai { 2957308ec68SBrian Somers /* Got a reset REQ, reset outgoing dictionary */ 296aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 29703036ec7SBrian Somers if (ccp->out.state != NULL) 29803036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); 299af57ed9fSAtsushi Murai } 300af57ed9fSAtsushi Murai 301af57ed9fSAtsushi Murai static void 302944f7098SBrian Somers CcpLayerStart(struct fsm *fp) 303af57ed9fSAtsushi Murai { 3047308ec68SBrian Somers /* We're about to start up ! */ 305dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CcpLayerStart.\n", fp->link->name); 306af57ed9fSAtsushi Murai } 307af57ed9fSAtsushi Murai 308af57ed9fSAtsushi Murai static void 309897f9429SBrian Somers CcpLayerDown(struct fsm *fp) 310af57ed9fSAtsushi Murai { 311897f9429SBrian Somers /* About to come down */ 312aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 313ba081e43SBrian Somers struct ccp_opt *next; 314ba081e43SBrian Somers 315897f9429SBrian Somers log_Printf(LogCCP, "%s: CcpLayerDown.\n", fp->link->name); 31603036ec7SBrian Somers if (ccp->in.state != NULL) { 31703036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); 31803036ec7SBrian Somers ccp->in.state = NULL; 3198d9b9867SBrian Somers ccp->in.algorithm = -1; 3207308ec68SBrian Somers } 32103036ec7SBrian Somers if (ccp->out.state != NULL) { 32203036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); 32303036ec7SBrian Somers ccp->out.state = NULL; 3248d9b9867SBrian Somers ccp->out.algorithm = -1; 3257308ec68SBrian Somers } 3268d9b9867SBrian Somers ccp->his_reject = ccp->my_reject = 0; 327ba081e43SBrian Somers 328ba081e43SBrian Somers while (ccp->out.opt) { 329ba081e43SBrian Somers next = ccp->out.opt->next; 330ba081e43SBrian Somers free(ccp->out.opt); 331ba081e43SBrian Somers ccp->out.opt = next; 332ba081e43SBrian Somers } 333897f9429SBrian Somers ccp_Setup(ccp); 334af57ed9fSAtsushi Murai } 335af57ed9fSAtsushi Murai 336af57ed9fSAtsushi Murai static void 337897f9429SBrian Somers CcpLayerFinish(struct fsm *fp) 338af57ed9fSAtsushi Murai { 339897f9429SBrian Somers /* We're now down */ 340897f9429SBrian Somers log_Printf(LogCCP, "%s: CcpLayerFinish.\n", fp->link->name); 341af57ed9fSAtsushi Murai } 342af57ed9fSAtsushi Murai 343af57ed9fSAtsushi Murai /* 3440053cc58SBrian Somers * Called when CCP has reached the OPEN state 345af57ed9fSAtsushi Murai */ 3466f384573SBrian Somers static int 347944f7098SBrian Somers CcpLayerUp(struct fsm *fp) 348af57ed9fSAtsushi Murai { 3497308ec68SBrian Somers /* We're now up */ 350aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 351dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CcpLayerUp.\n", fp->link->name); 35203036ec7SBrian Somers if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 35303036ec7SBrian Somers ccp->in.algorithm < NALGORITHMS) { 35403036ec7SBrian Somers ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 35503036ec7SBrian Somers if (ccp->in.state == NULL) { 356dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", 357d47dceb8SBrian Somers fp->link->name, protoname(ccp->his_proto)); 35883d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 359dd7e2610SBrian Somers fsm_Close(fp); 36079d1bdaeSBrian Somers } 361af57ed9fSAtsushi Murai } 362af57ed9fSAtsushi Murai 36303036ec7SBrian Somers if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 36403036ec7SBrian Somers ccp->out.algorithm < NALGORITHMS) { 36503036ec7SBrian Somers ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) 36603036ec7SBrian Somers (&ccp->out.opt->val); 36703036ec7SBrian Somers if (ccp->out.state == NULL) { 368dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", 369d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto)); 37083d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 371dd7e2610SBrian Somers fsm_Close(fp); 372247ab36dSBrian Somers } 373af57ed9fSAtsushi Murai } 374af57ed9fSAtsushi Murai 375dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 376d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 37783d1af55SBrian Somers protoname(ccp->his_proto), ccp->his_proto); 3786f384573SBrian Somers return 1; 379af57ed9fSAtsushi Murai } 380af57ed9fSAtsushi Murai 381af57ed9fSAtsushi Murai static void 38230c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 38330c2f2ffSBrian Somers struct fsm_decode *dec) 384af57ed9fSAtsushi Murai { 3857308ec68SBrian Somers /* Deal with incoming data */ 386aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 38753c9f6c0SAtsushi Murai int type, length; 3880053cc58SBrian Somers int f; 38903036ec7SBrian Somers const char *end; 390af57ed9fSAtsushi Murai 391af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 392af57ed9fSAtsushi Murai type = *cp; 393af57ed9fSAtsushi Murai length = cp[1]; 39403036ec7SBrian Somers 395d47dceb8SBrian Somers if (length == 0) { 396dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); 397d47dceb8SBrian Somers break; 398d47dceb8SBrian Somers } 399d47dceb8SBrian Somers 40003036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 40103036ec7SBrian Somers length = sizeof(struct lcp_opt); 402dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", 403d47dceb8SBrian Somers fp->link->name, length); 40403036ec7SBrian Somers } 405af57ed9fSAtsushi Murai 4060053cc58SBrian Somers for (f = NALGORITHMS-1; f > -1; f--) 4070053cc58SBrian Somers if (algorithm[f]->id == type) 4080053cc58SBrian Somers break; 409af57ed9fSAtsushi Murai 41003036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 41103036ec7SBrian Somers if (end == NULL) 41203036ec7SBrian Somers end = ""; 41303036ec7SBrian Somers 41403036ec7SBrian Somers if (type < NCFTYPES) 415dd7e2610SBrian Somers log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); 41603036ec7SBrian Somers else 417dd7e2610SBrian Somers log_Printf(LogCCP, " ???[%d] %s\n", length, end); 41803036ec7SBrian Somers 4190053cc58SBrian Somers if (f == -1) { 4200053cc58SBrian Somers /* Don't understand that :-( */ 4210053cc58SBrian Somers if (mode_type == MODE_REQ) { 42283d1af55SBrian Somers ccp->my_reject |= (1 << type); 42330c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 42430c2f2ffSBrian Somers dec->rejend += length; 4250053cc58SBrian Somers } 4260053cc58SBrian Somers } else { 42703036ec7SBrian Somers struct ccp_opt *o; 4280053cc58SBrian Somers 4299780ef31SBrian Somers switch (mode_type) { 430af57ed9fSAtsushi Murai case MODE_REQ: 4311342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 4321342caedSBrian Somers ccp->in.algorithm == -1) { 43303036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 43403036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 4350053cc58SBrian Somers case MODE_REJ: 43603036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 43703036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 4380053cc58SBrian Somers break; 4390053cc58SBrian Somers case MODE_NAK: 44003036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 44103036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 4420053cc58SBrian Somers break; 4430053cc58SBrian Somers case MODE_ACK: 44430c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 44530c2f2ffSBrian Somers dec->ackend += length; 44683d1af55SBrian Somers ccp->his_proto = type; 44703036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 4480053cc58SBrian Somers break; 4490053cc58SBrian Somers } 450af57ed9fSAtsushi Murai } else { 45130c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 45230c2f2ffSBrian Somers dec->rejend += length; 453af57ed9fSAtsushi Murai } 454af57ed9fSAtsushi Murai break; 455af57ed9fSAtsushi Murai case MODE_NAK: 45603036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 45703036ec7SBrian Somers if (o->val.id == cp[0]) 45803036ec7SBrian Somers break; 45903036ec7SBrian Somers if (o == NULL) 460dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n", 461d47dceb8SBrian Somers fp->link->name); 4620053cc58SBrian Somers else { 46303036ec7SBrian Somers memcpy(&o->val, cp, length); 46403036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 46583d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 4661ae349f5Scvs2svn else { 46783d1af55SBrian Somers ccp->his_reject |= (1 << type); 46883d1af55SBrian Somers ccp->my_proto = -1; 4691ae349f5Scvs2svn } 4700053cc58SBrian Somers } 4710053cc58SBrian Somers break; 472af57ed9fSAtsushi Murai case MODE_REJ: 47383d1af55SBrian Somers ccp->his_reject |= (1 << type); 47483d1af55SBrian Somers ccp->my_proto = -1; 475af57ed9fSAtsushi Murai break; 476af57ed9fSAtsushi Murai } 477af57ed9fSAtsushi Murai } 4780053cc58SBrian Somers 47903036ec7SBrian Somers plen -= cp[1]; 48003036ec7SBrian Somers cp += cp[1]; 481af57ed9fSAtsushi Murai } 4820053cc58SBrian Somers 483e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 4841342caedSBrian Somers if (dec->rejend != dec->rej) { 48503036ec7SBrian Somers /* rejects are preferred */ 48603036ec7SBrian Somers dec->ackend = dec->ack; 48703036ec7SBrian Somers dec->nakend = dec->nak; 48803036ec7SBrian Somers if (ccp->in.state == NULL) { 48983d1af55SBrian Somers ccp->his_proto = -1; 49003036ec7SBrian Somers ccp->in.algorithm = -1; 49103036ec7SBrian Somers } 4921342caedSBrian Somers } else if (dec->nakend != dec->nak) { 49303036ec7SBrian Somers /* then NAKs */ 49403036ec7SBrian Somers dec->ackend = dec->ack; 49503036ec7SBrian Somers if (ccp->in.state == NULL) { 49603036ec7SBrian Somers ccp->his_proto = -1; 49703036ec7SBrian Somers ccp->in.algorithm = -1; 498247ab36dSBrian Somers } 4991ae349f5Scvs2svn } 5000053cc58SBrian Somers } 501af57ed9fSAtsushi Murai } 502af57ed9fSAtsushi Murai 503af57ed9fSAtsushi Murai void 504dd7e2610SBrian Somers ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) 505af57ed9fSAtsushi Murai { 5067308ec68SBrian Somers /* Got PROTO_CCP from link */ 507455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 508dd7e2610SBrian Somers fsm_Input(&ccp->fsm, bp); 509af57ed9fSAtsushi Murai else { 510641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 511dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 512d47dceb8SBrian Somers ccp->fsm.link->name, bundle_PhaseName(bundle)); 513dd7e2610SBrian Somers mbuf_Free(bp); 514af57ed9fSAtsushi Murai } 515af57ed9fSAtsushi Murai } 5160053cc58SBrian Somers 517503a7782SBrian Somers static void 518503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 5190053cc58SBrian Somers { 5207308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 521f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 522f4768038SBrian Somers 523f4768038SBrian Somers if (ccp->reset_sent != -1) { 524f4768038SBrian Somers if (id != ccp->reset_sent) { 525dd7e2610SBrian Somers log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)" 526d47dceb8SBrian Somers " ignored\n", fp->link->name, id, ccp->reset_sent); 52798baf7c8SBrian Somers return; 52898baf7c8SBrian Somers } 52998baf7c8SBrian Somers /* Whaddaya know - a correct reset ack */ 530f4768038SBrian Somers } else if (id == ccp->last_reset) 531dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 532d47dceb8SBrian Somers fp->link->name); 53398baf7c8SBrian Somers else { 534dd7e2610SBrian Somers log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n", 535d47dceb8SBrian Somers fp->link->name, id); 53698baf7c8SBrian Somers return; 53798baf7c8SBrian Somers } 53898baf7c8SBrian Somers 539f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 540f4768038SBrian Somers ccp->reset_sent = -1; 54103036ec7SBrian Somers if (ccp->in.state != NULL) 54203036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 5430053cc58SBrian Somers } 5440053cc58SBrian Somers 5450053cc58SBrian Somers int 5463b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto, 547503a7782SBrian Somers struct mbuf *m) 5480053cc58SBrian Somers { 5490a1b5c9dSBrian Somers /* 5500a1b5c9dSBrian Somers * Compress outgoing data. It's already deemed to be suitable Network 5510a1b5c9dSBrian Somers * Layer data. 5520a1b5c9dSBrian Somers */ 5530a1b5c9dSBrian Somers if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL) 55403036ec7SBrian Somers return (*algorithm[ccp->out.algorithm]->o.Write) 55503036ec7SBrian Somers (ccp->out.state, ccp, l, pri, proto, m); 5560053cc58SBrian Somers return 0; 5570053cc58SBrian Somers } 5580053cc58SBrian Somers 5590053cc58SBrian Somers struct mbuf * 560503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) 5610053cc58SBrian Somers { 562ee6c193fSBrian Somers /* 563ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 564ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 565ee6c193fSBrian Somers */ 566e43ebac1SBrian Somers if (ccp->fsm.state == ST_OPENED) { 567ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 5687308ec68SBrian Somers /* Decompress incoming data */ 5692267893fSBrian Somers if (ccp->reset_sent != -1) 57098baf7c8SBrian Somers /* Send another REQ and put the packet in the bit bucket */ 571dd7e2610SBrian Somers fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); 5722267893fSBrian Somers else if (ccp->in.state != NULL) 57303036ec7SBrian Somers return (*algorithm[ccp->in.algorithm]->i.Read) 57403036ec7SBrian Somers (ccp->in.state, ccp, proto, bp); 575dd7e2610SBrian Somers mbuf_Free(bp); 576ee6c193fSBrian Somers bp = NULL; 5770a1b5c9dSBrian Somers } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL) 578ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 57903036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.DictSetup) 58003036ec7SBrian Somers (ccp->in.state, ccp, *proto, bp); 5810053cc58SBrian Somers } 5820053cc58SBrian Somers 583ee6c193fSBrian Somers return bp; 5841ae349f5Scvs2svn } 585ed32233cSBrian Somers 586ed32233cSBrian Somers u_short 587ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 5880053cc58SBrian Somers { 589ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 590ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 5910053cc58SBrian Somers } 5921df0a3b9SBrian Somers 5931df0a3b9SBrian Somers void 5941df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp) 5951df0a3b9SBrian Somers { 5961df0a3b9SBrian Somers int f; 5971df0a3b9SBrian Somers 5981df0a3b9SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 5991df0a3b9SBrian Somers if (ccp->cfg.neg[f]) 6001df0a3b9SBrian Somers ccp->fsm.open_mode = 0; 6011df0a3b9SBrian Somers 6021df0a3b9SBrian Somers ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED */ 6031df0a3b9SBrian Somers } 604