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 * 2097d92980SPeter Wemm * $FreeBSD$ 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> 33eb6e5e05SBrian Somers #include <string.h> /* memcpy() on some archs */ 3485b542cfSBrian Somers #include <termios.h> 3575240ed1SBrian Somers 365d9e6103SBrian Somers #include "layer.h" 37c9e11a11SBrian Somers #include "defs.h" 38b6e82f33SBrian Somers #include "command.h" 3975240ed1SBrian Somers #include "mbuf.h" 4075240ed1SBrian Somers #include "log.h" 4175240ed1SBrian Somers #include "timer.h" 42af57ed9fSAtsushi Murai #include "fsm.h" 435d9e6103SBrian Somers #include "proto.h" 44af57ed9fSAtsushi Murai #include "lcp.h" 45af57ed9fSAtsushi Murai #include "ccp.h" 46ed6a16c1SPoul-Henning Kamp #include "pred.h" 470053cc58SBrian Somers #include "deflate.h" 485828db6dSBrian Somers #include "throughput.h" 495828db6dSBrian Somers #include "iplist.h" 50eaa4df37SBrian Somers #include "slcompress.h" 515a72b6edSBrian Somers #include "lqr.h" 525a72b6edSBrian Somers #include "hdlc.h" 535828db6dSBrian Somers #include "ipcp.h" 545ca5389aSBrian Somers #include "filter.h" 5585b542cfSBrian Somers #include "descriptor.h" 5685b542cfSBrian Somers #include "prompt.h" 57503a7782SBrian Somers #include "link.h" 583b0f8d2eSBrian Somers #include "mp.h" 59ed32233cSBrian Somers #include "async.h" 60ed32233cSBrian Somers #include "physical.h" 61972a1bcfSBrian Somers #ifndef NORADIUS 62972a1bcfSBrian Somers #include "radius.h" 63972a1bcfSBrian Somers #endif 643b0f8d2eSBrian Somers #include "bundle.h" 65af57ed9fSAtsushi Murai 66927145beSBrian Somers static void CcpSendConfigReq(struct fsm *); 672267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *); 682267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char); 6930c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int, 7030c2f2ffSBrian Somers struct fsm_decode *); 71927145beSBrian Somers static void CcpLayerStart(struct fsm *); 72927145beSBrian Somers static void CcpLayerFinish(struct fsm *); 736f384573SBrian Somers static int CcpLayerUp(struct fsm *); 74927145beSBrian Somers static void CcpLayerDown(struct fsm *); 75479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int); 76503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *); 77503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char); 78af57ed9fSAtsushi Murai 7983d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = { 80af57ed9fSAtsushi Murai CcpLayerUp, 81af57ed9fSAtsushi Murai CcpLayerDown, 82af57ed9fSAtsushi Murai CcpLayerStart, 83af57ed9fSAtsushi Murai CcpLayerFinish, 84af57ed9fSAtsushi Murai CcpInitRestartCounter, 85af57ed9fSAtsushi Murai CcpSendConfigReq, 862267893fSBrian Somers CcpSentTerminateReq, 87af57ed9fSAtsushi Murai CcpSendTerminateAck, 88af57ed9fSAtsushi Murai CcpDecodeConfig, 89503a7782SBrian Somers CcpRecvResetReq, 90503a7782SBrian Somers CcpRecvResetAck 91af57ed9fSAtsushi Murai }; 92af57ed9fSAtsushi Murai 936f384573SBrian Somers static const char *ccp_TimerNames[] = 946f384573SBrian Somers {"CCP restart", "CCP openmode", "CCP stopped"}; 956f384573SBrian Somers 96e53374eaSPoul-Henning Kamp static char const *cftypes[] = { 979e836af5SBrian Somers /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 989e836af5SBrian Somers "OUI", /* 0: OUI */ 999e836af5SBrian Somers "PRED1", /* 1: Predictor type 1 */ 1009e836af5SBrian Somers "PRED2", /* 2: Predictor type 2 */ 1019e836af5SBrian Somers "PUDDLE", /* 3: Puddle Jumber */ 1029e836af5SBrian Somers "???", "???", "???", "???", "???", "???", 1039e836af5SBrian Somers "???", "???", "???", "???", "???", "???", 1049e836af5SBrian Somers "HWPPC", /* 16: Hewlett-Packard PPC */ 1054bc84b8cSBrian Somers "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 1068f2e5827SBrian Somers "MPPC", /* 18: Microsoft PPC (rfc2118) */ 1074bc84b8cSBrian Somers "GAND", /* 19: Gandalf FZA (rfc1993) */ 108b6e82f33SBrian Somers "V42BIS", /* 20: ARG->DATA.42bis compression */ 1090053cc58SBrian Somers "BSD", /* 21: BSD LZW Compress */ 1100053cc58SBrian Somers "???", 1114bc84b8cSBrian Somers "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 1124bc84b8cSBrian Somers "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 1131342caedSBrian Somers /* 24: Deflate (according to pppd-2.3.*) */ 1144bc84b8cSBrian Somers "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 1154bc84b8cSBrian Somers "DEFLATE", /* 26: Deflate (rfc1979) */ 116af57ed9fSAtsushi Murai }; 117af57ed9fSAtsushi Murai 11870ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 1199e836af5SBrian Somers 1200053cc58SBrian Somers static const char * 1210053cc58SBrian Somers protoname(int proto) 1220053cc58SBrian Somers { 1230053cc58SBrian Somers if (proto < 0 || proto > NCFTYPES) 1240053cc58SBrian Somers return "none"; 1250053cc58SBrian Somers return cftypes[proto]; 1260053cc58SBrian Somers } 1270053cc58SBrian Somers 1284bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */ 1290053cc58SBrian Somers static const struct ccp_algorithm *algorithm[] = { 1304bc84b8cSBrian Somers &DeflateAlgorithm, 1310053cc58SBrian Somers &Pred1Algorithm, 1324bc84b8cSBrian Somers &PppdDeflateAlgorithm 1330053cc58SBrian Somers }; 1340053cc58SBrian Somers 13570ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 1360053cc58SBrian Somers 137274e766cSBrian Somers int 138503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg) 139af57ed9fSAtsushi Murai { 140dd0645c5SBrian Somers struct link *l; 141dd0645c5SBrian Somers struct ccp *ccp; 142dd0645c5SBrian Somers 1433a2e4f62SBrian Somers l = command_ChooseLink(arg); 144dd0645c5SBrian Somers ccp = &l->ccp; 145503a7782SBrian Somers 146b6217683SBrian Somers prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, 1471e991daaSBrian Somers State2Nam(ccp->fsm.state)); 1485d9e6103SBrian Somers if (ccp->fsm.state == ST_OPENED) { 149b6217683SBrian Somers prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", 150503a7782SBrian Somers protoname(ccp->my_proto), protoname(ccp->his_proto)); 151b6217683SBrian Somers prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", 152503a7782SBrian Somers ccp->uncompout, ccp->compout, 153503a7782SBrian Somers ccp->compin, ccp->uncompin); 1545d9e6103SBrian Somers } 155cd9647a1SBrian Somers 156b6217683SBrian Somers prompt_Printf(arg->prompt, "\n Defaults: "); 157479508cfSBrian Somers prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config" 158479508cfSBrian Somers " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout, 159479508cfSBrian Somers ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s", 160479508cfSBrian Somers ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s"); 161b6217683SBrian Somers prompt_Printf(arg->prompt, " deflate windows: "); 162b6217683SBrian Somers prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); 163b6217683SBrian Somers prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); 1641342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE: %s\n", 1651342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); 1661342caedSBrian Somers prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", 1671342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); 1681342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE24: %s\n", 1691342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); 170274e766cSBrian Somers return 0; 171af57ed9fSAtsushi Murai } 172af57ed9fSAtsushi Murai 1731ae349f5Scvs2svn void 1746f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp) 175af57ed9fSAtsushi Murai { 1766f384573SBrian Somers ccp->fsm.fn = &ccp_Callbacks; 1776f384573SBrian Somers ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; 1786f384573SBrian Somers ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; 1796f384573SBrian Somers ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; 180ea661041SBrian Somers } 181ea661041SBrian Somers 182ea661041SBrian Somers void 1836d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, 1846d666775SBrian Somers const struct fsm_parent *parent) 185ea661041SBrian Somers { 1867308ec68SBrian Somers /* Initialise ourselves */ 1873b0f8d2eSBrian Somers 188479508cfSBrian Somers fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP, 1896f384573SBrian Somers bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); 190cd9647a1SBrian Somers 19103036ec7SBrian Somers ccp->cfg.deflate.in.winsize = 0; 19203036ec7SBrian Somers ccp->cfg.deflate.out.winsize = 15; 193479508cfSBrian Somers ccp->cfg.fsm.timeout = DEF_FSMRETRY; 194479508cfSBrian Somers ccp->cfg.fsm.maxreq = DEF_FSMTRIES; 195479508cfSBrian Somers ccp->cfg.fsm.maxtrm = DEF_FSMTRIES; 1961342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; 1971342caedSBrian Somers ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; 1981342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; 199cd9647a1SBrian Somers 200503a7782SBrian Somers ccp_Setup(ccp); 201503a7782SBrian Somers } 202503a7782SBrian Somers 203503a7782SBrian Somers void 204503a7782SBrian Somers ccp_Setup(struct ccp *ccp) 205503a7782SBrian Somers { 206503a7782SBrian Somers /* Set ourselves up for a startup */ 207503a7782SBrian Somers ccp->fsm.open_mode = 0; 208503a7782SBrian Somers ccp->his_proto = ccp->my_proto = -1; 209503a7782SBrian Somers ccp->reset_sent = ccp->last_reset = -1; 21003036ec7SBrian Somers ccp->in.algorithm = ccp->out.algorithm = -1; 21103036ec7SBrian Somers ccp->in.state = ccp->out.state = NULL; 21203036ec7SBrian Somers ccp->in.opt.id = -1; 21303036ec7SBrian Somers ccp->out.opt = NULL; 214503a7782SBrian Somers ccp->his_reject = ccp->my_reject = 0; 215503a7782SBrian Somers ccp->uncompout = ccp->compout = 0; 216503a7782SBrian Somers ccp->uncompin = ccp->compin = 0; 217af57ed9fSAtsushi Murai } 218af57ed9fSAtsushi Murai 219af57ed9fSAtsushi Murai static void 220479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what) 221af57ed9fSAtsushi Murai { 2227308ec68SBrian Somers /* Set fsm timer load */ 223cd9647a1SBrian Somers struct ccp *ccp = fsm2ccp(fp); 224cd9647a1SBrian Somers 225479508cfSBrian Somers fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS; 226479508cfSBrian Somers switch (what) { 227479508cfSBrian Somers case FSM_REQ_TIMER: 228479508cfSBrian Somers fp->restart = ccp->cfg.fsm.maxreq; 229479508cfSBrian Somers break; 230479508cfSBrian Somers case FSM_TRM_TIMER: 231479508cfSBrian Somers fp->restart = ccp->cfg.fsm.maxtrm; 232479508cfSBrian Somers break; 233479508cfSBrian Somers default: 234479508cfSBrian Somers fp->restart = 1; 235479508cfSBrian Somers break; 236479508cfSBrian Somers } 237af57ed9fSAtsushi Murai } 238af57ed9fSAtsushi Murai 239af57ed9fSAtsushi Murai static void 240944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp) 241af57ed9fSAtsushi Murai { 2427308ec68SBrian Somers /* Send config REQ please */ 243aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 24403036ec7SBrian Somers struct ccp_opt **o; 24530c2f2ffSBrian Somers u_char *cp, buff[100]; 24603036ec7SBrian Somers int f, alloc; 247af57ed9fSAtsushi Murai 24830c2f2ffSBrian Somers cp = buff; 24903036ec7SBrian Somers o = &ccp->out.opt; 25003036ec7SBrian Somers alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; 25183d1af55SBrian Somers ccp->my_proto = -1; 25203036ec7SBrian Somers ccp->out.algorithm = -1; 2530053cc58SBrian Somers for (f = 0; f < NALGORITHMS; f++) 2541342caedSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && 2551342caedSBrian Somers !REJECTED(ccp, algorithm[f]->id)) { 2560053cc58SBrian Somers 257ba081e43SBrian Somers if (!alloc) 258ba081e43SBrian Somers for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) 259ba081e43SBrian Somers if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) 260ba081e43SBrian Somers break; 261ba081e43SBrian Somers 262ba081e43SBrian Somers if (alloc || *o == NULL) { 26303036ec7SBrian Somers *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); 26403036ec7SBrian Somers (*o)->val.id = algorithm[f]->id; 26503036ec7SBrian Somers (*o)->val.len = 2; 26603036ec7SBrian Somers (*o)->next = NULL; 26703036ec7SBrian Somers (*o)->algorithm = f; 26803036ec7SBrian Somers (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); 269af57ed9fSAtsushi Murai } 2701ae349f5Scvs2svn 27103036ec7SBrian Somers if (cp + (*o)->val.len > buff + sizeof buff) { 272dd7e2610SBrian Somers log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); 27330c2f2ffSBrian Somers break; 27430c2f2ffSBrian Somers } 2752267893fSBrian Somers memcpy(cp, &(*o)->val, (*o)->val.len); 2762267893fSBrian Somers cp += (*o)->val.len; 27703036ec7SBrian Somers 27803036ec7SBrian Somers ccp->my_proto = (*o)->val.id; 27903036ec7SBrian Somers ccp->out.algorithm = f; 28003036ec7SBrian Somers 28103036ec7SBrian Somers if (alloc) 28203036ec7SBrian Somers o = &(*o)->next; 2831ae349f5Scvs2svn } 2842267893fSBrian Somers 285411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT); 286af57ed9fSAtsushi Murai } 287af57ed9fSAtsushi Murai 288af57ed9fSAtsushi Murai void 289dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp) 290af57ed9fSAtsushi Murai { 2917308ec68SBrian Somers /* We can't read our input - ask peer to reset */ 292aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 2932267893fSBrian Somers 29483d1af55SBrian Somers ccp->reset_sent = fp->reqid; 29583d1af55SBrian Somers ccp->last_reset = -1; 296411675baSBrian Somers fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT); 297af57ed9fSAtsushi Murai } 298af57ed9fSAtsushi Murai 299af57ed9fSAtsushi Murai static void 3002267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp) 301af57ed9fSAtsushi Murai { 3027308ec68SBrian Somers /* Term REQ just sent by FSM */ 303af57ed9fSAtsushi Murai } 304af57ed9fSAtsushi Murai 305af57ed9fSAtsushi Murai static void 3062267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id) 307af57ed9fSAtsushi Murai { 3087308ec68SBrian Somers /* Send Term ACK please */ 309411675baSBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT); 310af57ed9fSAtsushi Murai } 311af57ed9fSAtsushi Murai 312503a7782SBrian Somers static void 313944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp) 314af57ed9fSAtsushi Murai { 3157308ec68SBrian Somers /* Got a reset REQ, reset outgoing dictionary */ 316aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 31703036ec7SBrian Somers if (ccp->out.state != NULL) 31803036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); 319af57ed9fSAtsushi Murai } 320af57ed9fSAtsushi Murai 321af57ed9fSAtsushi Murai static void 322944f7098SBrian Somers CcpLayerStart(struct fsm *fp) 323af57ed9fSAtsushi Murai { 3247308ec68SBrian Somers /* We're about to start up ! */ 325479508cfSBrian Somers struct ccp *ccp = fsm2ccp(fp); 326479508cfSBrian Somers 3273a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); 328479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; 329af57ed9fSAtsushi Murai } 330af57ed9fSAtsushi Murai 331af57ed9fSAtsushi Murai static void 332897f9429SBrian Somers CcpLayerDown(struct fsm *fp) 333af57ed9fSAtsushi Murai { 334897f9429SBrian Somers /* About to come down */ 335aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 336ba081e43SBrian Somers struct ccp_opt *next; 337ba081e43SBrian Somers 3383a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); 33903036ec7SBrian Somers if (ccp->in.state != NULL) { 34003036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); 34103036ec7SBrian Somers ccp->in.state = NULL; 3428d9b9867SBrian Somers ccp->in.algorithm = -1; 3437308ec68SBrian Somers } 34403036ec7SBrian Somers if (ccp->out.state != NULL) { 34503036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); 34603036ec7SBrian Somers ccp->out.state = NULL; 3478d9b9867SBrian Somers ccp->out.algorithm = -1; 3487308ec68SBrian Somers } 3498d9b9867SBrian Somers ccp->his_reject = ccp->my_reject = 0; 350ba081e43SBrian Somers 351ba081e43SBrian Somers while (ccp->out.opt) { 352ba081e43SBrian Somers next = ccp->out.opt->next; 353ba081e43SBrian Somers free(ccp->out.opt); 354ba081e43SBrian Somers ccp->out.opt = next; 355ba081e43SBrian Somers } 356897f9429SBrian Somers ccp_Setup(ccp); 357af57ed9fSAtsushi Murai } 358af57ed9fSAtsushi Murai 359af57ed9fSAtsushi Murai static void 360897f9429SBrian Somers CcpLayerFinish(struct fsm *fp) 361af57ed9fSAtsushi Murai { 362897f9429SBrian Somers /* We're now down */ 3633a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); 364af57ed9fSAtsushi Murai } 365af57ed9fSAtsushi Murai 3663377c28cSBrian Somers /* Called when CCP has reached the OPEN state */ 3676f384573SBrian Somers static int 368944f7098SBrian Somers CcpLayerUp(struct fsm *fp) 369af57ed9fSAtsushi Murai { 3707308ec68SBrian Somers /* We're now up */ 371aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 372479508cfSBrian Somers 3733a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); 374479508cfSBrian Somers 37503036ec7SBrian Somers if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 37603036ec7SBrian Somers ccp->in.algorithm < NALGORITHMS) { 37703036ec7SBrian Somers ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 37803036ec7SBrian Somers if (ccp->in.state == NULL) { 379dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", 380d47dceb8SBrian Somers fp->link->name, protoname(ccp->his_proto)); 38183d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 382dd7e2610SBrian Somers fsm_Close(fp); 383479508cfSBrian Somers return 0; 38479d1bdaeSBrian Somers } 385af57ed9fSAtsushi Murai } 386af57ed9fSAtsushi Murai 38703036ec7SBrian Somers if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 38803036ec7SBrian Somers ccp->out.algorithm < NALGORITHMS) { 38903036ec7SBrian Somers ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) 39003036ec7SBrian Somers (&ccp->out.opt->val); 39103036ec7SBrian Somers if (ccp->out.state == NULL) { 392dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", 393d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto)); 39483d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 395dd7e2610SBrian Somers fsm_Close(fp); 396479508cfSBrian Somers return 0; 397247ab36dSBrian Somers } 398af57ed9fSAtsushi Murai } 399af57ed9fSAtsushi Murai 400479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; 401479508cfSBrian Somers 402dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 403d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 40483d1af55SBrian Somers protoname(ccp->his_proto), ccp->his_proto); 405479508cfSBrian Somers 4066f384573SBrian Somers return 1; 407af57ed9fSAtsushi Murai } 408af57ed9fSAtsushi Murai 409af57ed9fSAtsushi Murai static void 41030c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 41130c2f2ffSBrian Somers struct fsm_decode *dec) 412af57ed9fSAtsushi Murai { 4137308ec68SBrian Somers /* Deal with incoming data */ 414aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 41531516407SBrian Somers int type, length, f; 41603036ec7SBrian Somers const char *end; 417af57ed9fSAtsushi Murai 41831516407SBrian Somers if (mode_type == MODE_REQ) 41931516407SBrian Somers ccp->in.algorithm = -1; /* In case we've received two REQs in a row */ 42031516407SBrian Somers 421af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 422af57ed9fSAtsushi Murai type = *cp; 423af57ed9fSAtsushi Murai length = cp[1]; 42403036ec7SBrian Somers 425d47dceb8SBrian Somers if (length == 0) { 426dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); 427d47dceb8SBrian Somers break; 428d47dceb8SBrian Somers } 429d47dceb8SBrian Somers 43003036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 43103036ec7SBrian Somers length = sizeof(struct lcp_opt); 432dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", 433d47dceb8SBrian Somers fp->link->name, length); 43403036ec7SBrian Somers } 435af57ed9fSAtsushi Murai 4360053cc58SBrian Somers for (f = NALGORITHMS-1; f > -1; f--) 4370053cc58SBrian Somers if (algorithm[f]->id == type) 4380053cc58SBrian Somers break; 439af57ed9fSAtsushi Murai 44003036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 44103036ec7SBrian Somers if (end == NULL) 44203036ec7SBrian Somers end = ""; 44303036ec7SBrian Somers 44403036ec7SBrian Somers if (type < NCFTYPES) 445dd7e2610SBrian Somers log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); 44603036ec7SBrian Somers else 447dd7e2610SBrian Somers log_Printf(LogCCP, " ???[%d] %s\n", length, end); 44803036ec7SBrian Somers 4490053cc58SBrian Somers if (f == -1) { 4500053cc58SBrian Somers /* Don't understand that :-( */ 4510053cc58SBrian Somers if (mode_type == MODE_REQ) { 45283d1af55SBrian Somers ccp->my_reject |= (1 << type); 45330c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 45430c2f2ffSBrian Somers dec->rejend += length; 4550053cc58SBrian Somers } 4560053cc58SBrian Somers } else { 45703036ec7SBrian Somers struct ccp_opt *o; 4580053cc58SBrian Somers 4599780ef31SBrian Somers switch (mode_type) { 460af57ed9fSAtsushi Murai case MODE_REQ: 4611342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 4621342caedSBrian Somers ccp->in.algorithm == -1) { 46303036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 46403036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 4650053cc58SBrian Somers case MODE_REJ: 46603036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 46703036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 4680053cc58SBrian Somers break; 4690053cc58SBrian Somers case MODE_NAK: 47003036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 47103036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 4720053cc58SBrian Somers break; 4730053cc58SBrian Somers case MODE_ACK: 47430c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 47530c2f2ffSBrian Somers dec->ackend += length; 47683d1af55SBrian Somers ccp->his_proto = type; 47703036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 4780053cc58SBrian Somers break; 4790053cc58SBrian Somers } 480af57ed9fSAtsushi Murai } else { 48130c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 48230c2f2ffSBrian Somers dec->rejend += length; 483af57ed9fSAtsushi Murai } 484af57ed9fSAtsushi Murai break; 485af57ed9fSAtsushi Murai case MODE_NAK: 48603036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 48703036ec7SBrian Somers if (o->val.id == cp[0]) 48803036ec7SBrian Somers break; 48903036ec7SBrian Somers if (o == NULL) 490dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n", 491d47dceb8SBrian Somers fp->link->name); 4920053cc58SBrian Somers else { 49303036ec7SBrian Somers memcpy(&o->val, cp, length); 49403036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 49583d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 4961ae349f5Scvs2svn else { 49783d1af55SBrian Somers ccp->his_reject |= (1 << type); 49883d1af55SBrian Somers ccp->my_proto = -1; 4991ae349f5Scvs2svn } 5000053cc58SBrian Somers } 5010053cc58SBrian Somers break; 502af57ed9fSAtsushi Murai case MODE_REJ: 50383d1af55SBrian Somers ccp->his_reject |= (1 << type); 50483d1af55SBrian Somers ccp->my_proto = -1; 505af57ed9fSAtsushi Murai break; 506af57ed9fSAtsushi Murai } 507af57ed9fSAtsushi Murai } 5080053cc58SBrian Somers 50903036ec7SBrian Somers plen -= cp[1]; 51003036ec7SBrian Somers cp += cp[1]; 511af57ed9fSAtsushi Murai } 5120053cc58SBrian Somers 513e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 5141342caedSBrian Somers if (dec->rejend != dec->rej) { 51503036ec7SBrian Somers /* rejects are preferred */ 51603036ec7SBrian Somers dec->ackend = dec->ack; 51703036ec7SBrian Somers dec->nakend = dec->nak; 51803036ec7SBrian Somers if (ccp->in.state == NULL) { 51983d1af55SBrian Somers ccp->his_proto = -1; 52003036ec7SBrian Somers ccp->in.algorithm = -1; 52103036ec7SBrian Somers } 5221342caedSBrian Somers } else if (dec->nakend != dec->nak) { 52303036ec7SBrian Somers /* then NAKs */ 52403036ec7SBrian Somers dec->ackend = dec->ack; 52503036ec7SBrian Somers if (ccp->in.state == NULL) { 52603036ec7SBrian Somers ccp->his_proto = -1; 52703036ec7SBrian Somers ccp->in.algorithm = -1; 528247ab36dSBrian Somers } 5291ae349f5Scvs2svn } 5300053cc58SBrian Somers } 531af57ed9fSAtsushi Murai } 532af57ed9fSAtsushi Murai 5335d9e6103SBrian Somers extern struct mbuf * 5345d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 535af57ed9fSAtsushi Murai { 5367308ec68SBrian Somers /* Got PROTO_CCP from link */ 53726af0ae9SBrian Somers m_settype(bp, MB_CCPIN); 538455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 5395d9e6103SBrian Somers fsm_Input(&l->ccp.fsm, bp); 540af57ed9fSAtsushi Murai else { 541641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 542dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 5435d9e6103SBrian Somers l->ccp.fsm.link->name, bundle_PhaseName(bundle)); 54426af0ae9SBrian Somers m_freem(bp); 545af57ed9fSAtsushi Murai } 5465d9e6103SBrian Somers return NULL; 547af57ed9fSAtsushi Murai } 5480053cc58SBrian Somers 549503a7782SBrian Somers static void 550503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 5510053cc58SBrian Somers { 5527308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 553f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 554f4768038SBrian Somers 555f4768038SBrian Somers if (ccp->reset_sent != -1) { 556f4768038SBrian Somers if (id != ccp->reset_sent) { 557a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)" 558d47dceb8SBrian Somers " ignored\n", fp->link->name, id, ccp->reset_sent); 55998baf7c8SBrian Somers return; 56098baf7c8SBrian Somers } 56198baf7c8SBrian Somers /* Whaddaya know - a correct reset ack */ 562f4768038SBrian Somers } else if (id == ccp->last_reset) 563dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 564d47dceb8SBrian Somers fp->link->name); 56598baf7c8SBrian Somers else { 566a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n", 567d47dceb8SBrian Somers fp->link->name, id); 56898baf7c8SBrian Somers return; 56998baf7c8SBrian Somers } 57098baf7c8SBrian Somers 571f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 572f4768038SBrian Somers ccp->reset_sent = -1; 57303036ec7SBrian Somers if (ccp->in.state != NULL) 57403036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 5750053cc58SBrian Somers } 5760053cc58SBrian Somers 5775d9e6103SBrian Somers static struct mbuf * 5785d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, 5795d9e6103SBrian Somers int pri, u_short *proto) 5800053cc58SBrian Somers { 5815d9e6103SBrian Somers if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED && 582411675baSBrian Somers l->ccp.out.state != NULL) { 583411675baSBrian Somers bp = (*algorithm[l->ccp.out.algorithm]->o.Write) 5845d9e6103SBrian Somers (l->ccp.out.state, &l->ccp, l, pri, proto, bp); 585411675baSBrian Somers switch (*proto) { 586411675baSBrian Somers case PROTO_ICOMPD: 58726af0ae9SBrian Somers m_settype(bp, MB_ICOMPDOUT); 588411675baSBrian Somers break; 589411675baSBrian Somers case PROTO_COMPD: 59026af0ae9SBrian Somers m_settype(bp, MB_COMPDOUT); 591411675baSBrian Somers break; 592411675baSBrian Somers } 593411675baSBrian Somers } 5945d9e6103SBrian Somers 5955d9e6103SBrian Somers return bp; 5960053cc58SBrian Somers } 5970053cc58SBrian Somers 5985d9e6103SBrian Somers static struct mbuf * 5995d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) 6000053cc58SBrian Somers { 601ee6c193fSBrian Somers /* 602ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 603ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 604ee6c193fSBrian Somers */ 6055d9e6103SBrian Somers if (l->ccp.fsm.state == ST_OPENED) { 606ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 6076815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n", 6086815097bSBrian Somers *proto == PROTO_ICOMPD ? "I" : ""); 6097308ec68SBrian Somers /* Decompress incoming data */ 6105d9e6103SBrian Somers if (l->ccp.reset_sent != -1) 61198baf7c8SBrian Somers /* Send another REQ and put the packet in the bit bucket */ 612411675baSBrian Somers fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0, 613411675baSBrian Somers MB_CCPOUT); 614411675baSBrian Somers else if (l->ccp.in.state != NULL) { 615411675baSBrian Somers bp = (*algorithm[l->ccp.in.algorithm]->i.Read) 6165d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, proto, bp); 617411675baSBrian Somers switch (*proto) { 618411675baSBrian Somers case PROTO_ICOMPD: 61926af0ae9SBrian Somers m_settype(bp, MB_ICOMPDIN); 620411675baSBrian Somers break; 621411675baSBrian Somers case PROTO_COMPD: 62226af0ae9SBrian Somers m_settype(bp, MB_COMPDIN); 623411675baSBrian Somers break; 624411675baSBrian Somers } 625411675baSBrian Somers return bp; 626411675baSBrian Somers } 62726af0ae9SBrian Somers m_freem(bp); 628ee6c193fSBrian Somers bp = NULL; 6296815097bSBrian Somers } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) { 6306815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n"); 631ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 6325d9e6103SBrian Somers (*algorithm[l->ccp.in.algorithm]->i.DictSetup) 6335d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, *proto, bp); 6346815097bSBrian Somers } else 6356815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n"); 6360053cc58SBrian Somers } 6370053cc58SBrian Somers 638ee6c193fSBrian Somers return bp; 6391ae349f5Scvs2svn } 640ed32233cSBrian Somers 641ed32233cSBrian Somers u_short 642ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 6430053cc58SBrian Somers { 644ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 645ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 6460053cc58SBrian Somers } 6471df0a3b9SBrian Somers 64806337856SBrian Somers int 6491df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp) 6501df0a3b9SBrian Somers { 6511df0a3b9SBrian Somers int f; 6521df0a3b9SBrian Somers 6531df0a3b9SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 65406337856SBrian Somers if (IsEnabled(ccp->cfg.neg[f])) { 6551df0a3b9SBrian Somers ccp->fsm.open_mode = 0; 65606337856SBrian Somers return 1; 65706337856SBrian Somers } 6581df0a3b9SBrian Somers 65906337856SBrian Somers ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ 66006337856SBrian Somers 66106337856SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 66206337856SBrian Somers if (IsAccepted(ccp->cfg.neg[f])) 66306337856SBrian Somers return 1; 66406337856SBrian Somers 66506337856SBrian Somers return 0; /* No CCP at all */ 6661df0a3b9SBrian Somers } 6675d9e6103SBrian Somers 6685d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull }; 669