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 178ba6fcad9SBrian Somers prompt_Printf(arg->prompt, " MPPE: %s", 179a8d604abSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE])); 180ba6fcad9SBrian 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 */ 379e1e8b15eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 380e1e8b15eSBrian Somers struct ccp_opt *next; 381e1e8b15eSBrian Somers 3823a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); 383e1e8b15eSBrian Somers 384e1e8b15eSBrian Somers /* 385e1e8b15eSBrian Somers * Nuke options that may be left over from sending a REQ but never 386e1e8b15eSBrian Somers * coming up. 387e1e8b15eSBrian Somers */ 388e1e8b15eSBrian Somers while (ccp->out.opt) { 389e1e8b15eSBrian Somers next = ccp->out.opt->next; 390e1e8b15eSBrian Somers free(ccp->out.opt); 391e1e8b15eSBrian Somers ccp->out.opt = next; 392e1e8b15eSBrian Somers } 393af57ed9fSAtsushi Murai } 394af57ed9fSAtsushi Murai 3953377c28cSBrian Somers /* Called when CCP has reached the OPEN state */ 3966f384573SBrian Somers static int 397944f7098SBrian Somers CcpLayerUp(struct fsm *fp) 398af57ed9fSAtsushi Murai { 3997308ec68SBrian Somers /* We're now up */ 400aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 401e1e8b15eSBrian Somers struct ccp_opt **o; 402e1e8b15eSBrian Somers int f; 403479508cfSBrian Somers 4043a2e4f62SBrian Somers log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); 405479508cfSBrian Somers 40603036ec7SBrian Somers if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 40703036ec7SBrian Somers ccp->in.algorithm < NALGORITHMS) { 40803036ec7SBrian Somers ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 40903036ec7SBrian Somers if (ccp->in.state == NULL) { 410dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", 411d47dceb8SBrian Somers fp->link->name, protoname(ccp->his_proto)); 41283d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 413dd7e2610SBrian Somers fsm_Close(fp); 414479508cfSBrian Somers return 0; 41579d1bdaeSBrian Somers } 416af57ed9fSAtsushi Murai } 417af57ed9fSAtsushi Murai 418e1e8b15eSBrian Somers o = &ccp->out.opt; 419e1e8b15eSBrian Somers for (f = 0; f < ccp->out.algorithm; f++) 420e1e8b15eSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg])) 421e1e8b15eSBrian Somers o = &(*o)->next; 422e1e8b15eSBrian Somers 42303036ec7SBrian Somers if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 42403036ec7SBrian Somers ccp->out.algorithm < NALGORITHMS) { 425e1e8b15eSBrian Somers ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)(&(*o)->val); 42603036ec7SBrian Somers if (ccp->out.state == NULL) { 427dd7e2610SBrian Somers log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", 428d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto)); 42983d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 430dd7e2610SBrian Somers fsm_Close(fp); 431479508cfSBrian Somers return 0; 432247ab36dSBrian Somers } 433af57ed9fSAtsushi Murai } 434af57ed9fSAtsushi Murai 435479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3; 436479508cfSBrian Somers 437dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 438d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 43983d1af55SBrian Somers protoname(ccp->his_proto), ccp->his_proto); 440479508cfSBrian Somers 4416f384573SBrian Somers return 1; 442af57ed9fSAtsushi Murai } 443af57ed9fSAtsushi Murai 444af57ed9fSAtsushi Murai static void 44530c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 44630c2f2ffSBrian Somers struct fsm_decode *dec) 447af57ed9fSAtsushi Murai { 4487308ec68SBrian Somers /* Deal with incoming data */ 449aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 45031516407SBrian Somers int type, length, f; 45103036ec7SBrian Somers const char *end; 452af57ed9fSAtsushi Murai 45331516407SBrian Somers if (mode_type == MODE_REQ) 45431516407SBrian Somers ccp->in.algorithm = -1; /* In case we've received two REQs in a row */ 45531516407SBrian Somers 456af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 457af57ed9fSAtsushi Murai type = *cp; 458af57ed9fSAtsushi Murai length = cp[1]; 45903036ec7SBrian Somers 460d47dceb8SBrian Somers if (length == 0) { 461dd7e2610SBrian Somers log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); 462d47dceb8SBrian Somers break; 463d47dceb8SBrian Somers } 464d47dceb8SBrian Somers 46503036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 46603036ec7SBrian Somers length = sizeof(struct lcp_opt); 467dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", 468d47dceb8SBrian Somers fp->link->name, length); 46903036ec7SBrian Somers } 470af57ed9fSAtsushi Murai 4710053cc58SBrian Somers for (f = NALGORITHMS-1; f > -1; f--) 4720053cc58SBrian Somers if (algorithm[f]->id == type) 4730053cc58SBrian Somers break; 474af57ed9fSAtsushi Murai 47503036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 47603036ec7SBrian Somers if (end == NULL) 47703036ec7SBrian Somers end = ""; 47803036ec7SBrian Somers 479d6d3eeabSBrian Somers log_Printf(LogCCP, " %s[%d] %s\n", protoname(type), length, end); 48003036ec7SBrian Somers 4810053cc58SBrian Somers if (f == -1) { 4820053cc58SBrian Somers /* Don't understand that :-( */ 4830053cc58SBrian Somers if (mode_type == MODE_REQ) { 48483d1af55SBrian Somers ccp->my_reject |= (1 << type); 48530c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 48630c2f2ffSBrian Somers dec->rejend += length; 4870053cc58SBrian Somers } 4880053cc58SBrian Somers } else { 48903036ec7SBrian Somers struct ccp_opt *o; 4900053cc58SBrian Somers 4919780ef31SBrian Somers switch (mode_type) { 492af57ed9fSAtsushi Murai case MODE_REQ: 4931342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 4941342caedSBrian Somers ccp->in.algorithm == -1) { 49503036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 49603036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 4970053cc58SBrian Somers case MODE_REJ: 49803036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 49903036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 5000053cc58SBrian Somers break; 5010053cc58SBrian Somers case MODE_NAK: 50203036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 50303036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 5040053cc58SBrian Somers break; 5050053cc58SBrian Somers case MODE_ACK: 50630c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 50730c2f2ffSBrian Somers dec->ackend += length; 50883d1af55SBrian Somers ccp->his_proto = type; 50903036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 5100053cc58SBrian Somers break; 5110053cc58SBrian Somers } 512af57ed9fSAtsushi Murai } else { 51330c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 51430c2f2ffSBrian Somers dec->rejend += length; 515af57ed9fSAtsushi Murai } 516af57ed9fSAtsushi Murai break; 517af57ed9fSAtsushi Murai case MODE_NAK: 51803036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 51903036ec7SBrian Somers if (o->val.id == cp[0]) 52003036ec7SBrian Somers break; 52103036ec7SBrian Somers if (o == NULL) 5229b996792SBrian Somers log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent" 5239b996792SBrian Somers " option\n", fp->link->name); 5240053cc58SBrian Somers else { 52503036ec7SBrian Somers memcpy(&o->val, cp, length); 52603036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 52783d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 5281ae349f5Scvs2svn else { 52983d1af55SBrian Somers ccp->his_reject |= (1 << type); 53083d1af55SBrian Somers ccp->my_proto = -1; 5311ae349f5Scvs2svn } 5320053cc58SBrian Somers } 5330053cc58SBrian Somers break; 534af57ed9fSAtsushi Murai case MODE_REJ: 53583d1af55SBrian Somers ccp->his_reject |= (1 << type); 53683d1af55SBrian Somers ccp->my_proto = -1; 537af57ed9fSAtsushi Murai break; 538af57ed9fSAtsushi Murai } 539af57ed9fSAtsushi Murai } 5400053cc58SBrian Somers 54103036ec7SBrian Somers plen -= cp[1]; 54203036ec7SBrian Somers cp += cp[1]; 543af57ed9fSAtsushi Murai } 5440053cc58SBrian Somers 545e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 5461342caedSBrian Somers if (dec->rejend != dec->rej) { 54703036ec7SBrian Somers /* rejects are preferred */ 54803036ec7SBrian Somers dec->ackend = dec->ack; 54903036ec7SBrian Somers dec->nakend = dec->nak; 55003036ec7SBrian Somers if (ccp->in.state == NULL) { 55183d1af55SBrian Somers ccp->his_proto = -1; 55203036ec7SBrian Somers ccp->in.algorithm = -1; 55303036ec7SBrian Somers } 5541342caedSBrian Somers } else if (dec->nakend != dec->nak) { 55503036ec7SBrian Somers /* then NAKs */ 55603036ec7SBrian Somers dec->ackend = dec->ack; 55703036ec7SBrian Somers if (ccp->in.state == NULL) { 55803036ec7SBrian Somers ccp->his_proto = -1; 55903036ec7SBrian Somers ccp->in.algorithm = -1; 560247ab36dSBrian Somers } 5611ae349f5Scvs2svn } 5620053cc58SBrian Somers } 563af57ed9fSAtsushi Murai } 564af57ed9fSAtsushi Murai 5655d9e6103SBrian Somers extern struct mbuf * 5665d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 567af57ed9fSAtsushi Murai { 5687308ec68SBrian Somers /* Got PROTO_CCP from link */ 56926af0ae9SBrian Somers m_settype(bp, MB_CCPIN); 570455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 5715d9e6103SBrian Somers fsm_Input(&l->ccp.fsm, bp); 572af57ed9fSAtsushi Murai else { 573641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 574dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 5755d9e6103SBrian Somers l->ccp.fsm.link->name, bundle_PhaseName(bundle)); 57626af0ae9SBrian Somers m_freem(bp); 577af57ed9fSAtsushi Murai } 5785d9e6103SBrian Somers return NULL; 579af57ed9fSAtsushi Murai } 5800053cc58SBrian Somers 581503a7782SBrian Somers static void 582503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 5830053cc58SBrian Somers { 5847308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 585f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 586f4768038SBrian Somers 587f4768038SBrian Somers if (ccp->reset_sent != -1) { 588f4768038SBrian Somers if (id != ccp->reset_sent) { 589a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)" 590d47dceb8SBrian Somers " ignored\n", fp->link->name, id, ccp->reset_sent); 59198baf7c8SBrian Somers return; 59298baf7c8SBrian Somers } 59398baf7c8SBrian Somers /* Whaddaya know - a correct reset ack */ 594f4768038SBrian Somers } else if (id == ccp->last_reset) 595dd7e2610SBrian Somers log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 596d47dceb8SBrian Somers fp->link->name); 59798baf7c8SBrian Somers else { 598a36ca3ccSBrian Somers log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n", 599d47dceb8SBrian Somers fp->link->name, id); 60098baf7c8SBrian Somers return; 60198baf7c8SBrian Somers } 60298baf7c8SBrian Somers 603f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 604f4768038SBrian Somers ccp->reset_sent = -1; 60503036ec7SBrian Somers if (ccp->in.state != NULL) 60603036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 6070053cc58SBrian Somers } 6080053cc58SBrian Somers 6095d9e6103SBrian Somers static struct mbuf * 6105d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp, 6115d9e6103SBrian Somers int pri, u_short *proto) 6120053cc58SBrian Somers { 6135d9e6103SBrian Somers if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED && 614411675baSBrian Somers l->ccp.out.state != NULL) { 615411675baSBrian Somers bp = (*algorithm[l->ccp.out.algorithm]->o.Write) 6165d9e6103SBrian Somers (l->ccp.out.state, &l->ccp, l, pri, proto, bp); 617411675baSBrian Somers switch (*proto) { 618411675baSBrian Somers case PROTO_ICOMPD: 61926af0ae9SBrian Somers m_settype(bp, MB_ICOMPDOUT); 620411675baSBrian Somers break; 621411675baSBrian Somers case PROTO_COMPD: 62226af0ae9SBrian Somers m_settype(bp, MB_COMPDOUT); 623411675baSBrian Somers break; 624411675baSBrian Somers } 625411675baSBrian Somers } 6265d9e6103SBrian Somers 6275d9e6103SBrian Somers return bp; 6280053cc58SBrian Somers } 6290053cc58SBrian Somers 6305d9e6103SBrian Somers static struct mbuf * 6315d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) 6320053cc58SBrian Somers { 633ee6c193fSBrian Somers /* 634ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 635ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 636ee6c193fSBrian Somers */ 6375d9e6103SBrian Somers if (l->ccp.fsm.state == ST_OPENED) { 638ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 6396815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n", 6406815097bSBrian Somers *proto == PROTO_ICOMPD ? "I" : ""); 6417308ec68SBrian Somers /* Decompress incoming data */ 6425d9e6103SBrian Somers if (l->ccp.reset_sent != -1) 64398baf7c8SBrian Somers /* Send another REQ and put the packet in the bit bucket */ 644411675baSBrian Somers fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0, 645411675baSBrian Somers MB_CCPOUT); 646411675baSBrian Somers else if (l->ccp.in.state != NULL) { 647411675baSBrian Somers bp = (*algorithm[l->ccp.in.algorithm]->i.Read) 6485d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, proto, bp); 649411675baSBrian Somers switch (*proto) { 650411675baSBrian Somers case PROTO_ICOMPD: 65126af0ae9SBrian Somers m_settype(bp, MB_ICOMPDIN); 652411675baSBrian Somers break; 653411675baSBrian Somers case PROTO_COMPD: 65426af0ae9SBrian Somers m_settype(bp, MB_COMPDIN); 655411675baSBrian Somers break; 656411675baSBrian Somers } 657411675baSBrian Somers return bp; 658411675baSBrian Somers } 65926af0ae9SBrian Somers m_freem(bp); 660ee6c193fSBrian Somers bp = NULL; 6616815097bSBrian Somers } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) { 6626815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n"); 663ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 6645d9e6103SBrian Somers (*algorithm[l->ccp.in.algorithm]->i.DictSetup) 6655d9e6103SBrian Somers (l->ccp.in.state, &l->ccp, *proto, bp); 6666815097bSBrian Somers } else 6676815097bSBrian Somers log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n"); 6680053cc58SBrian Somers } 6690053cc58SBrian Somers 670ee6c193fSBrian Somers return bp; 6711ae349f5Scvs2svn } 672ed32233cSBrian Somers 673ed32233cSBrian Somers u_short 674ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 6750053cc58SBrian Somers { 676ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 677ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 6780053cc58SBrian Somers } 6791df0a3b9SBrian Somers 68006337856SBrian Somers int 6811df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp) 6821df0a3b9SBrian Somers { 6831df0a3b9SBrian Somers int f; 6841df0a3b9SBrian Somers 6851df0a3b9SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 68606337856SBrian Somers if (IsEnabled(ccp->cfg.neg[f])) { 6871df0a3b9SBrian Somers ccp->fsm.open_mode = 0; 68806337856SBrian Somers return 1; 68906337856SBrian Somers } 6901df0a3b9SBrian Somers 69106337856SBrian Somers ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ 69206337856SBrian Somers 69306337856SBrian Somers for (f = 0; f < CCP_NEG_TOTAL; f++) 69406337856SBrian Somers if (IsAccepted(ccp->cfg.neg[f])) 69506337856SBrian Somers return 1; 69606337856SBrian Somers 69706337856SBrian Somers return 0; /* No CCP at all */ 6981df0a3b9SBrian Somers } 6995d9e6103SBrian Somers 7005d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull }; 701