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" 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" 495a72b6edSBrian Somers #include "lqr.h" 505a72b6edSBrian Somers #include "hdlc.h" 511038894eSBrian Somers #include "lcp.h" 521038894eSBrian Somers #include "ccp.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 64a8d604abSBrian Somers #ifdef HAVE_DES 65a8d604abSBrian Somers #include "mppe.h" 66a8d604abSBrian Somers #endif 673b0f8d2eSBrian Somers #include "bundle.h" 68af57ed9fSAtsushi Murai 69927145beSBrian Somers static void CcpSendConfigReq(struct fsm *); 702267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *); 712267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char); 7230c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int, 7330c2f2ffSBrian Somers struct fsm_decode *); 74927145beSBrian Somers static void CcpLayerStart(struct fsm *); 75927145beSBrian Somers static void CcpLayerFinish(struct fsm *); 766f384573SBrian Somers static int CcpLayerUp(struct fsm *); 77927145beSBrian Somers static void CcpLayerDown(struct fsm *); 78479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int); 79503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *); 80503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char); 81af57ed9fSAtsushi Murai 8283d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = { 83af57ed9fSAtsushi Murai CcpLayerUp, 84af57ed9fSAtsushi Murai CcpLayerDown, 85af57ed9fSAtsushi Murai CcpLayerStart, 86af57ed9fSAtsushi Murai CcpLayerFinish, 87af57ed9fSAtsushi Murai CcpInitRestartCounter, 88af57ed9fSAtsushi Murai CcpSendConfigReq, 892267893fSBrian Somers CcpSentTerminateReq, 90af57ed9fSAtsushi Murai CcpSendTerminateAck, 91af57ed9fSAtsushi Murai CcpDecodeConfig, 92503a7782SBrian Somers CcpRecvResetReq, 93503a7782SBrian Somers CcpRecvResetAck 94af57ed9fSAtsushi Murai }; 95af57ed9fSAtsushi Murai 96182c898aSBrian Somers static const char * const ccp_TimerNames[] = 976f384573SBrian Somers {"CCP restart", "CCP openmode", "CCP stopped"}; 986f384573SBrian Somers 99d6d3eeabSBrian Somers static const char * 100d6d3eeabSBrian Somers protoname(int proto) 101d6d3eeabSBrian Somers { 102182c898aSBrian Somers static char const * const cftypes[] = { 103d6d3eeabSBrian Somers /* Check out the latest ``Compression Control Protocol'' rfc (1962) */ 1049e836af5SBrian Somers "OUI", /* 0: OUI */ 1059e836af5SBrian Somers "PRED1", /* 1: Predictor type 1 */ 1069e836af5SBrian Somers "PRED2", /* 2: Predictor type 2 */ 1079e836af5SBrian Somers "PUDDLE", /* 3: Puddle Jumber */ 108d6d3eeabSBrian Somers NULL, NULL, NULL, NULL, NULL, NULL, 109d6d3eeabSBrian Somers NULL, NULL, NULL, NULL, NULL, NULL, 1109e836af5SBrian Somers "HWPPC", /* 16: Hewlett-Packard PPC */ 1114bc84b8cSBrian Somers "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 112a8d604abSBrian Somers "MPPE", /* 18: Microsoft PPC (rfc2118) and */ 113a8d604abSBrian Somers /* Microsoft PPE (draft-ietf-pppext-mppe) */ 1144bc84b8cSBrian Somers "GAND", /* 19: Gandalf FZA (rfc1993) */ 115b6e82f33SBrian Somers "V42BIS", /* 20: ARG->DATA.42bis compression */ 1160053cc58SBrian Somers "BSD", /* 21: BSD LZW Compress */ 117d6d3eeabSBrian Somers NULL, 1184bc84b8cSBrian Somers "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 1194bc84b8cSBrian Somers "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */ 1201342caedSBrian Somers /* 24: Deflate (according to pppd-2.3.*) */ 1214bc84b8cSBrian Somers "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 1224bc84b8cSBrian Somers "DEFLATE", /* 26: Deflate (rfc1979) */ 123af57ed9fSAtsushi Murai }; 124af57ed9fSAtsushi Murai 125d6d3eeabSBrian Somers if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes || 126d6d3eeabSBrian Somers cftypes[proto] == NULL) 127d6d3eeabSBrian Somers return HexStr(proto, NULL, 0); 1289e836af5SBrian Somers 1290053cc58SBrian Somers return cftypes[proto]; 1300053cc58SBrian Somers } 1310053cc58SBrian Somers 1324bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */ 133182c898aSBrian Somers static const struct ccp_algorithm * const algorithm[] = { 1344bc84b8cSBrian Somers &DeflateAlgorithm, 1350053cc58SBrian Somers &Pred1Algorithm, 1364bc84b8cSBrian Somers &PppdDeflateAlgorithm 137a8d604abSBrian Somers #ifdef HAVE_DES 138a8d604abSBrian Somers , &MPPEAlgorithm 139a8d604abSBrian Somers #endif 1400053cc58SBrian Somers }; 1410053cc58SBrian Somers 14270ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 1430053cc58SBrian Somers 144274e766cSBrian Somers int 145503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg) 146af57ed9fSAtsushi Murai { 147dd0645c5SBrian Somers struct link *l; 148dd0645c5SBrian Somers struct ccp *ccp; 149dd0645c5SBrian Somers 1503a2e4f62SBrian Somers l = command_ChooseLink(arg); 151dd0645c5SBrian Somers ccp = &l->ccp; 152503a7782SBrian Somers 153b6217683SBrian Somers prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, 1541e991daaSBrian Somers State2Nam(ccp->fsm.state)); 1555d9e6103SBrian Somers if (ccp->fsm.state == ST_OPENED) { 156b6217683SBrian Somers prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", 157503a7782SBrian Somers protoname(ccp->my_proto), protoname(ccp->his_proto)); 158b6217683SBrian Somers prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", 159503a7782SBrian Somers ccp->uncompout, ccp->compout, 160503a7782SBrian Somers ccp->compin, ccp->uncompin); 1615d9e6103SBrian Somers } 162cd9647a1SBrian Somers 163b6217683SBrian Somers prompt_Printf(arg->prompt, "\n Defaults: "); 164479508cfSBrian Somers prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config" 165479508cfSBrian Somers " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout, 166479508cfSBrian Somers ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s", 167479508cfSBrian Somers ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s"); 168b6217683SBrian Somers prompt_Printf(arg->prompt, " deflate windows: "); 169b6217683SBrian Somers prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); 170b6217683SBrian Somers prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); 1711342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE: %s\n", 1721342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); 1731342caedSBrian Somers prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", 1741342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); 1751342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE24: %s\n", 1761342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); 177a8d604abSBrian Somers #ifdef HAVE_DES 178a8d604abSBrian Somers prompt_Printf(arg->prompt, " MPPE: %s\n", 179a8d604abSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE])); 180a8d604abSBrian Somers prompt_Printf(arg->prompt, "Key Size = %d-bits\n", ccp->cfg.mppe.keybits); 181a8d604abSBrian Somers #endif 182274e766cSBrian Somers return 0; 183af57ed9fSAtsushi Murai } 184af57ed9fSAtsushi Murai 1851ae349f5Scvs2svn void 1866f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp) 187af57ed9fSAtsushi Murai { 1886f384573SBrian Somers ccp->fsm.fn = &ccp_Callbacks; 1896f384573SBrian Somers ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; 1906f384573SBrian Somers ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; 1916f384573SBrian Somers ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; 192ea661041SBrian Somers } 193ea661041SBrian Somers 194ea661041SBrian Somers void 1956d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, 1966d666775SBrian Somers const struct fsm_parent *parent) 197ea661041SBrian Somers { 1987308ec68SBrian Somers /* Initialise ourselves */ 1993b0f8d2eSBrian Somers 200479508cfSBrian Somers fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP, 2016f384573SBrian Somers bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); 202cd9647a1SBrian Somers 20303036ec7SBrian Somers ccp->cfg.deflate.in.winsize = 0; 20403036ec7SBrian Somers ccp->cfg.deflate.out.winsize = 15; 205479508cfSBrian Somers ccp->cfg.fsm.timeout = DEF_FSMRETRY; 206479508cfSBrian Somers ccp->cfg.fsm.maxreq = DEF_FSMTRIES; 207479508cfSBrian Somers ccp->cfg.fsm.maxtrm = DEF_FSMTRIES; 2081342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; 2091342caedSBrian Somers ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; 2101342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; 211a8d604abSBrian Somers #ifdef HAVE_DES 212a8d604abSBrian Somers ccp->cfg.mppe.keybits = 128; 213a8d604abSBrian Somers ccp->cfg.neg[CCP_NEG_MPPE] = 0; 214a8d604abSBrian Somers #endif 215cd9647a1SBrian Somers 216503a7782SBrian Somers ccp_Setup(ccp); 217503a7782SBrian Somers } 218503a7782SBrian Somers 219503a7782SBrian Somers void 220503a7782SBrian Somers ccp_Setup(struct ccp *ccp) 221503a7782SBrian Somers { 222503a7782SBrian Somers /* Set ourselves up for a startup */ 223503a7782SBrian Somers ccp->fsm.open_mode = 0; 224503a7782SBrian Somers ccp->his_proto = ccp->my_proto = -1; 225503a7782SBrian Somers ccp->reset_sent = ccp->last_reset = -1; 22603036ec7SBrian Somers ccp->in.algorithm = ccp->out.algorithm = -1; 22703036ec7SBrian Somers ccp->in.state = ccp->out.state = NULL; 22803036ec7SBrian Somers ccp->in.opt.id = -1; 22903036ec7SBrian Somers ccp->out.opt = NULL; 230503a7782SBrian Somers ccp->his_reject = ccp->my_reject = 0; 231503a7782SBrian Somers ccp->uncompout = ccp->compout = 0; 232503a7782SBrian Somers ccp->uncompin = ccp->compin = 0; 233af57ed9fSAtsushi Murai } 234af57ed9fSAtsushi Murai 235af57ed9fSAtsushi Murai static void 236479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what) 237af57ed9fSAtsushi Murai { 2387308ec68SBrian Somers /* Set fsm timer load */ 239cd9647a1SBrian Somers struct ccp *ccp = fsm2ccp(fp); 240cd9647a1SBrian Somers 241479508cfSBrian Somers fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS; 242479508cfSBrian Somers switch (what) { 243479508cfSBrian Somers case FSM_REQ_TIMER: 244479508cfSBrian Somers fp->restart = ccp->cfg.fsm.maxreq; 245479508cfSBrian Somers break; 246479508cfSBrian Somers case FSM_TRM_TIMER: 247479508cfSBrian Somers fp->restart = ccp->cfg.fsm.maxtrm; 248479508cfSBrian Somers break; 249479508cfSBrian Somers default: 250479508cfSBrian Somers fp->restart = 1; 251479508cfSBrian Somers break; 252479508cfSBrian Somers } 253af57ed9fSAtsushi Murai } 254af57ed9fSAtsushi Murai 255af57ed9fSAtsushi Murai static void 256944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp) 257af57ed9fSAtsushi Murai { 2587308ec68SBrian Somers /* Send config REQ please */ 259aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 26003036ec7SBrian Somers struct ccp_opt **o; 26130c2f2ffSBrian Somers u_char *cp, buff[100]; 26203036ec7SBrian Somers int f, alloc; 263af57ed9fSAtsushi Murai 26430c2f2ffSBrian Somers cp = buff; 26503036ec7SBrian Somers o = &ccp->out.opt; 26603036ec7SBrian Somers alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; 26783d1af55SBrian Somers ccp->my_proto = -1; 26803036ec7SBrian Somers ccp->out.algorithm = -1; 2690053cc58SBrian Somers for (f = 0; f < NALGORITHMS; f++) 2701342caedSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && 2711342caedSBrian Somers !REJECTED(ccp, algorithm[f]->id)) { 2720053cc58SBrian Somers 273ba081e43SBrian Somers if (!alloc) 274ba081e43SBrian Somers for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) 275ba081e43SBrian Somers if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) 276ba081e43SBrian Somers break; 277ba081e43SBrian Somers 278ba081e43SBrian Somers if (alloc || *o == NULL) { 27903036ec7SBrian Somers *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); 28003036ec7SBrian Somers (*o)->val.id = algorithm[f]->id; 28103036ec7SBrian Somers (*o)->val.len = 2; 28203036ec7SBrian Somers (*o)->next = NULL; 28303036ec7SBrian Somers (*o)->algorithm = f; 28403036ec7SBrian Somers (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); 285af57ed9fSAtsushi Murai } 2861ae349f5Scvs2svn 28703036ec7SBrian Somers if (cp + (*o)->val.len > buff + sizeof buff) { 288dd7e2610SBrian Somers log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); 28930c2f2ffSBrian Somers break; 29030c2f2ffSBrian Somers } 2912267893fSBrian Somers memcpy(cp, &(*o)->val, (*o)->val.len); 2922267893fSBrian Somers cp += (*o)->val.len; 29303036ec7SBrian Somers 29403036ec7SBrian Somers ccp->my_proto = (*o)->val.id; 29503036ec7SBrian Somers ccp->out.algorithm = f; 29603036ec7SBrian Somers 29703036ec7SBrian Somers if (alloc) 29803036ec7SBrian Somers o = &(*o)->next; 2991ae349f5Scvs2svn } 3002267893fSBrian Somers 301411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT); 302af57ed9fSAtsushi Murai } 303af57ed9fSAtsushi Murai 304af57ed9fSAtsushi Murai void 305dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp) 306af57ed9fSAtsushi Murai { 3077308ec68SBrian Somers /* We can't read our input - ask peer to reset */ 308aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 3092267893fSBrian Somers 31083d1af55SBrian Somers ccp->reset_sent = fp->reqid; 31183d1af55SBrian Somers ccp->last_reset = -1; 312411675baSBrian Somers fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT); 313af57ed9fSAtsushi Murai } 314af57ed9fSAtsushi Murai 315af57ed9fSAtsushi Murai static void 3162267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp) 317af57ed9fSAtsushi Murai { 3187308ec68SBrian Somers /* Term REQ just sent by FSM */ 319af57ed9fSAtsushi Murai } 320af57ed9fSAtsushi Murai 321af57ed9fSAtsushi Murai static void 3222267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id) 323af57ed9fSAtsushi Murai { 3247308ec68SBrian Somers /* Send Term ACK please */ 325411675baSBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT); 326af57ed9fSAtsushi Murai } 327af57ed9fSAtsushi Murai 328503a7782SBrian Somers static void 329944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp) 330af57ed9fSAtsushi Murai { 3317308ec68SBrian Somers /* Got a reset REQ, reset outgoing dictionary */ 332aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 33303036ec7SBrian Somers if (ccp->out.state != NULL) 33403036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); 335af57ed9fSAtsushi Murai } 336af57ed9fSAtsushi Murai 337af57ed9fSAtsushi Murai static void 338944f7098SBrian Somers CcpLayerStart(struct fsm *fp) 339af57ed9fSAtsushi Murai { 3407308ec68SBrian Somers /* We're about to start up ! */ 341479508cfSBrian Somers struct ccp *ccp = fsm2ccp(fp); 342479508cfSBrian Somers 3433a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); 344479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; 345af57ed9fSAtsushi Murai } 346af57ed9fSAtsushi Murai 347af57ed9fSAtsushi Murai static void 348897f9429SBrian Somers CcpLayerDown(struct fsm *fp) 349af57ed9fSAtsushi Murai { 350897f9429SBrian Somers /* About to come down */ 351aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 352ba081e43SBrian Somers struct ccp_opt *next; 353ba081e43SBrian Somers 3543a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); 35503036ec7SBrian Somers if (ccp->in.state != NULL) { 35603036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); 35703036ec7SBrian Somers ccp->in.state = NULL; 3588d9b9867SBrian Somers ccp->in.algorithm = -1; 3597308ec68SBrian Somers } 36003036ec7SBrian Somers if (ccp->out.state != NULL) { 36103036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); 36203036ec7SBrian Somers ccp->out.state = NULL; 3638d9b9867SBrian Somers ccp->out.algorithm = -1; 3647308ec68SBrian Somers } 3658d9b9867SBrian Somers ccp->his_reject = ccp->my_reject = 0; 366ba081e43SBrian Somers 367ba081e43SBrian Somers while (ccp->out.opt) { 368ba081e43SBrian Somers next = ccp->out.opt->next; 369ba081e43SBrian Somers free(ccp->out.opt); 370ba081e43SBrian Somers ccp->out.opt = next; 371ba081e43SBrian Somers } 372897f9429SBrian Somers ccp_Setup(ccp); 373af57ed9fSAtsushi Murai } 374af57ed9fSAtsushi Murai 375af57ed9fSAtsushi Murai static void 376897f9429SBrian Somers CcpLayerFinish(struct fsm *fp) 377af57ed9fSAtsushi Murai { 378897f9429SBrian Somers /* We're now down */ 3793a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); 380af57ed9fSAtsushi Murai } 381af57ed9fSAtsushi Murai 3823377c28cSBrian Somers /* Called when CCP has reached the OPEN state */ 3836f384573SBrian Somers static int 384944f7098SBrian Somers CcpLayerUp(struct fsm *fp) 385af57ed9fSAtsushi Murai { 3867308ec68SBrian Somers /* We're now up */ 387aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 388479508cfSBrian Somers 3893a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); 390479508cfSBrian Somers 39103036ec7SBrian Somers if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 39203036ec7SBrian Somers ccp->in.algorithm < NALGORITHMS) { 39303036ec7SBrian Somers ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 39403036ec7SBrian Somers if (ccp->in.state == NULL) { 395dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", 396d47dceb8SBrian Somers fp->link->name, protoname(ccp->his_proto)); 39783d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 398dd7e2610SBrian Somers fsm_Close(fp); 399479508cfSBrian Somers return 0; 40079d1bdaeSBrian Somers } 401af57ed9fSAtsushi Murai } 402af57ed9fSAtsushi Murai 40303036ec7SBrian Somers if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 40403036ec7SBrian Somers ccp->out.algorithm < NALGORITHMS) { 40503036ec7SBrian Somers ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) 40603036ec7SBrian Somers (&ccp->out.opt->val); 40703036ec7SBrian Somers if (ccp->out.state == NULL) { 408dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", 409d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto)); 41083d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 411dd7e2610SBrian Somers fsm_Close(fp); 412479508cfSBrian Somers return 0; 413247ab36dSBrian Somers } 414af57ed9fSAtsushi Murai } 415af57ed9fSAtsushi Murai 416479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; 417479508cfSBrian Somers 418dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 419d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 42083d1af55SBrian Somers protoname(ccp->his_proto), ccp->his_proto); 421479508cfSBrian Somers 4226f384573SBrian Somers return 1; 423af57ed9fSAtsushi Murai } 424af57ed9fSAtsushi Murai 425af57ed9fSAtsushi Murai static void 42630c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 42730c2f2ffSBrian Somers struct fsm_decode *dec) 428af57ed9fSAtsushi Murai { 4297308ec68SBrian Somers /* Deal with incoming data */ 430aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 43131516407SBrian Somers int type, length, f; 43203036ec7SBrian Somers const char *end; 433af57ed9fSAtsushi Murai 43431516407SBrian Somers if (mode_type == MODE_REQ) 43531516407SBrian Somers ccp->in.algorithm = -1; /* In case we've received two REQs in a row */ 43631516407SBrian Somers 437af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 438af57ed9fSAtsushi Murai type = *cp; 439af57ed9fSAtsushi Murai length = cp[1]; 44003036ec7SBrian Somers 441d47dceb8SBrian Somers if (length == 0) { 442dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); 443d47dceb8SBrian Somers break; 444d47dceb8SBrian Somers } 445d47dceb8SBrian Somers 44603036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 44703036ec7SBrian Somers length = sizeof(struct lcp_opt); 448dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", 449d47dceb8SBrian Somers fp->link->name, length); 45003036ec7SBrian Somers } 451af57ed9fSAtsushi Murai 4520053cc58SBrian Somers for (f = NALGORITHMS-1; f > -1; f--) 4530053cc58SBrian Somers if (algorithm[f]->id == type) 4540053cc58SBrian Somers break; 455af57ed9fSAtsushi Murai 45603036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 45703036ec7SBrian Somers if (end == NULL) 45803036ec7SBrian Somers end = ""; 45903036ec7SBrian Somers 460d6d3eeabSBrian Somers log_Printf(LogCCP, " %s[%d] %s\n", protoname(type), length, end); 46103036ec7SBrian Somers 4620053cc58SBrian Somers if (f == -1) { 4630053cc58SBrian Somers /* Don't understand that :-( */ 4640053cc58SBrian Somers if (mode_type == MODE_REQ) { 46583d1af55SBrian Somers ccp->my_reject |= (1 << type); 46630c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 46730c2f2ffSBrian Somers dec->rejend += length; 4680053cc58SBrian Somers } 4690053cc58SBrian Somers } else { 47003036ec7SBrian Somers struct ccp_opt *o; 4710053cc58SBrian Somers 4729780ef31SBrian Somers switch (mode_type) { 473af57ed9fSAtsushi Murai case MODE_REQ: 4741342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 4751342caedSBrian Somers ccp->in.algorithm == -1) { 47603036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 47703036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 4780053cc58SBrian Somers case MODE_REJ: 47903036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 48003036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 4810053cc58SBrian Somers break; 4820053cc58SBrian Somers case MODE_NAK: 48303036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 48403036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 4850053cc58SBrian Somers break; 4860053cc58SBrian Somers case MODE_ACK: 48730c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 48830c2f2ffSBrian Somers dec->ackend += length; 48983d1af55SBrian Somers ccp->his_proto = type; 49003036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 4910053cc58SBrian Somers break; 4920053cc58SBrian Somers } 493af57ed9fSAtsushi Murai } else { 49430c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 49530c2f2ffSBrian Somers dec->rejend += length; 496af57ed9fSAtsushi Murai } 497af57ed9fSAtsushi Murai break; 498af57ed9fSAtsushi Murai case MODE_NAK: 49903036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 50003036ec7SBrian Somers if (o->val.id == cp[0]) 50103036ec7SBrian Somers break; 50203036ec7SBrian Somers if (o == NULL) 5039b996792SBrian Somers log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent" 5049b996792SBrian Somers " option\n", fp->link->name); 5050053cc58SBrian Somers else { 50603036ec7SBrian Somers memcpy(&o->val, cp, length); 50703036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 50883d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 5091ae349f5Scvs2svn else { 51083d1af55SBrian Somers ccp->his_reject |= (1 << type); 51183d1af55SBrian Somers ccp->my_proto = -1; 5121ae349f5Scvs2svn } 5130053cc58SBrian Somers } 5140053cc58SBrian Somers break; 515af57ed9fSAtsushi Murai case MODE_REJ: 51683d1af55SBrian Somers ccp->his_reject |= (1 << type); 51783d1af55SBrian Somers ccp->my_proto = -1; 518af57ed9fSAtsushi Murai break; 519af57ed9fSAtsushi Murai } 520af57ed9fSAtsushi Murai } 5210053cc58SBrian Somers 52203036ec7SBrian Somers plen -= cp[1]; 52303036ec7SBrian Somers cp += cp[1]; 524af57ed9fSAtsushi Murai } 5250053cc58SBrian Somers 526e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 5271342caedSBrian Somers if (dec->rejend != dec->rej) { 52803036ec7SBrian Somers /* rejects are preferred */ 52903036ec7SBrian Somers dec->ackend = dec->ack; 53003036ec7SBrian Somers dec->nakend = dec->nak; 53103036ec7SBrian Somers if (ccp->in.state == NULL) { 53283d1af55SBrian Somers ccp->his_proto = -1; 53303036ec7SBrian Somers ccp->in.algorithm = -1; 53403036ec7SBrian Somers } 5351342caedSBrian Somers } else if (dec->nakend != dec->nak) { 53603036ec7SBrian Somers /* then NAKs */ 53703036ec7SBrian Somers dec->ackend = dec->ack; 53803036ec7SBrian Somers if (ccp->in.state == NULL) { 53903036ec7SBrian Somers ccp->his_proto = -1; 54003036ec7SBrian Somers ccp->in.algorithm = -1; 541247ab36dSBrian Somers } 5421ae349f5Scvs2svn } 5430053cc58SBrian Somers } 544af57ed9fSAtsushi Murai } 545af57ed9fSAtsushi Murai 5465d9e6103SBrian Somers extern struct mbuf * 5475d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 548af57ed9fSAtsushi Murai { 5497308ec68SBrian Somers /* Got PROTO_CCP from link */ 55026af0ae9SBrian Somers m_settype(bp, MB_CCPIN); 551455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 5525d9e6103SBrian Somers fsm_Input(&l->ccp.fsm, bp); 553af57ed9fSAtsushi Murai else { 554641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 555dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 5565d9e6103SBrian Somers l->ccp.fsm.link->name, bundle_PhaseName(bundle)); 55726af0ae9SBrian Somers m_freem(bp); 558af57ed9fSAtsushi Murai } 5595d9e6103SBrian Somers return NULL; 560af57ed9fSAtsushi Murai } 5610053cc58SBrian Somers 562503a7782SBrian Somers static void 563503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 5640053cc58SBrian Somers { 5657308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 566f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 567f4768038SBrian Somers 568f4768038SBrian Somers if (ccp->reset_sent != -1) { 569f4768038SBrian Somers if (id != ccp->reset_sent) { 570a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)" 571d47dceb8SBrian Somers " ignored\n", fp->link->name, id, ccp->reset_sent); 57298baf7c8SBrian Somers return; 57398baf7c8SBrian Somers } 57498baf7c8SBrian Somers /* Whaddaya know - a correct reset ack */ 575f4768038SBrian Somers } else if (id == ccp->last_reset) 576dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 577d47dceb8SBrian Somers fp->link->name); 57898baf7c8SBrian Somers else { 579a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n", 580d47dceb8SBrian Somers fp->link->name, id); 58198baf7c8SBrian Somers return; 58298baf7c8SBrian Somers } 58398baf7c8SBrian Somers 584f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 585f4768038SBrian Somers ccp->reset_sent = -1; 58603036ec7SBrian Somers if (ccp->in.state != NULL) 58703036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 5880053cc58SBrian Somers } 5890053cc58SBrian Somers 5905d9e6103SBrian Somers static struct mbuf * 5915d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, 5925d9e6103SBrian Somers int pri, u_short *proto) 5930053cc58SBrian Somers { 5945d9e6103SBrian Somers if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED && 595411675baSBrian Somers l->ccp.out.state != NULL) { 596411675baSBrian Somers bp = (*algorithm[l->ccp.out.algorithm]->o.Write) 5975d9e6103SBrian Somers (l->ccp.out.state, &l->ccp, l, pri, proto, bp); 598411675baSBrian Somers switch (*proto) { 599411675baSBrian Somers case PROTO_ICOMPD: 60026af0ae9SBrian Somers m_settype(bp, MB_ICOMPDOUT); 601411675baSBrian Somers break; 602411675baSBrian Somers case PROTO_COMPD: 60326af0ae9SBrian Somers m_settype(bp, MB_COMPDOUT); 604411675baSBrian Somers break; 605411675baSBrian Somers } 606411675baSBrian Somers } 6075d9e6103SBrian Somers 6085d9e6103SBrian Somers return bp; 6090053cc58SBrian Somers } 6100053cc58SBrian Somers 6115d9e6103SBrian Somers static struct mbuf * 6125d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) 6130053cc58SBrian Somers { 614ee6c193fSBrian Somers /* 615ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 616ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 617ee6c193fSBrian Somers */ 6185d9e6103SBrian Somers if (l->ccp.fsm.state == ST_OPENED) { 619ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 6206815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n", 6216815097bSBrian Somers *proto == PROTO_ICOMPD ? "I" : ""); 6227308ec68SBrian Somers /* Decompress incoming data */ 6235d9e6103SBrian Somers if (l->ccp.reset_sent != -1) 62498baf7c8SBrian Somers /* Send another REQ and put the packet in the bit bucket */ 625411675baSBrian Somers fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0, 626411675baSBrian Somers MB_CCPOUT); 627411675baSBrian Somers else if (l->ccp.in.state != NULL) { 628411675baSBrian Somers bp = (*algorithm[l->ccp.in.algorithm]->i.Read) 6295d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, proto, bp); 630411675baSBrian Somers switch (*proto) { 631411675baSBrian Somers case PROTO_ICOMPD: 63226af0ae9SBrian Somers m_settype(bp, MB_ICOMPDIN); 633411675baSBrian Somers break; 634411675baSBrian Somers case PROTO_COMPD: 63526af0ae9SBrian Somers m_settype(bp, MB_COMPDIN); 636411675baSBrian Somers break; 637411675baSBrian Somers } 638411675baSBrian Somers return bp; 639411675baSBrian Somers } 64026af0ae9SBrian Somers m_freem(bp); 641ee6c193fSBrian Somers bp = NULL; 6426815097bSBrian Somers } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) { 6436815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n"); 644ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 6455d9e6103SBrian Somers (*algorithm[l->ccp.in.algorithm]->i.DictSetup) 6465d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, *proto, bp); 6476815097bSBrian Somers } else 6486815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n"); 6490053cc58SBrian Somers } 6500053cc58SBrian Somers 651ee6c193fSBrian Somers return bp; 6521ae349f5Scvs2svn } 653ed32233cSBrian Somers 654ed32233cSBrian Somers u_short 655ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 6560053cc58SBrian Somers { 657ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 658ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 6590053cc58SBrian Somers } 6601df0a3b9SBrian Somers 66106337856SBrian Somers int 6621df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp) 6631df0a3b9SBrian Somers { 6641df0a3b9SBrian Somers int f; 6651df0a3b9SBrian Somers 6661df0a3b9SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 66706337856SBrian Somers if (IsEnabled(ccp->cfg.neg[f])) { 6681df0a3b9SBrian Somers ccp->fsm.open_mode = 0; 66906337856SBrian Somers return 1; 67006337856SBrian Somers } 6711df0a3b9SBrian Somers 67206337856SBrian Somers ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ 67306337856SBrian Somers 67406337856SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 67506337856SBrian Somers if (IsAccepted(ccp->cfg.neg[f])) 67606337856SBrian Somers return 1; 67706337856SBrian Somers 67806337856SBrian Somers return 0; /* No CCP at all */ 6791df0a3b9SBrian Somers } 6805d9e6103SBrian Somers 6815d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull }; 682