11ae349f5Scvs2svn /* 21ae349f5Scvs2svn * PPP Compression Control Protocol (CCP) Module 31ae349f5Scvs2svn * 41ae349f5Scvs2svn * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 51ae349f5Scvs2svn * 61ae349f5Scvs2svn * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 71ae349f5Scvs2svn * 81ae349f5Scvs2svn * Redistribution and use in source and binary forms are permitted 91ae349f5Scvs2svn * provided that the above copyright notice and this paragraph are 101ae349f5Scvs2svn * duplicated in all such forms and that any documentation, 111ae349f5Scvs2svn * advertising materials, and other materials related to such 121ae349f5Scvs2svn * distribution and use acknowledge that the software was developed 131ae349f5Scvs2svn * by the Internet Initiative Japan, Inc. The name of the 141ae349f5Scvs2svn * IIJ may not be used to endorse or promote products derived 151ae349f5Scvs2svn * from this software without specific prior written permission. 161ae349f5Scvs2svn * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 171ae349f5Scvs2svn * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 181ae349f5Scvs2svn * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 191ae349f5Scvs2svn * 20e43ebac1SBrian Somers * $Id: ccp.c,v 1.30.2.38 1998/04/24 19:15:36 brian Exp $ 211ae349f5Scvs2svn * 221ae349f5Scvs2svn * TODO: 231ae349f5Scvs2svn * o Support other compression protocols 241ae349f5Scvs2svn */ 252764b86aSBrian Somers #include <sys/types.h> 261ae349f5Scvs2svn #include <netinet/in.h> 27eaa4df37SBrian Somers #include <netinet/in_systm.h> 28eaa4df37SBrian Somers #include <netinet/ip.h> 291ae349f5Scvs2svn 301ae349f5Scvs2svn #include <stdio.h> 3103036ec7SBrian Somers #include <stdlib.h> 3285b542cfSBrian Somers #include <termios.h> 331ae349f5Scvs2svn 341ae349f5Scvs2svn #include "command.h" 351ae349f5Scvs2svn #include "mbuf.h" 361ae349f5Scvs2svn #include "log.h" 371ae349f5Scvs2svn #include "defs.h" 381ae349f5Scvs2svn #include "timer.h" 391ae349f5Scvs2svn #include "fsm.h" 401ae349f5Scvs2svn #include "lcpproto.h" 411ae349f5Scvs2svn #include "lcp.h" 421ae349f5Scvs2svn #include "ccp.h" 431ae349f5Scvs2svn #include "pred.h" 441ae349f5Scvs2svn #include "deflate.h" 455828db6dSBrian Somers #include "throughput.h" 465828db6dSBrian Somers #include "iplist.h" 47eaa4df37SBrian Somers #include "slcompress.h" 485828db6dSBrian Somers #include "ipcp.h" 495ca5389aSBrian Somers #include "filter.h" 5085b542cfSBrian Somers #include "descriptor.h" 5185b542cfSBrian Somers #include "prompt.h" 52879ed6faSBrian Somers #include "lqr.h" 53503a7782SBrian Somers #include "hdlc.h" 54503a7782SBrian Somers #include "link.h" 553b0f8d2eSBrian Somers #include "mp.h" 56ed32233cSBrian Somers #include "async.h" 57ed32233cSBrian Somers #include "physical.h" 583b0f8d2eSBrian Somers #include "bundle.h" 591ae349f5Scvs2svn 601ae349f5Scvs2svn static void CcpSendConfigReq(struct fsm *); 612267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *); 622267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char); 6330c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int, 6430c2f2ffSBrian Somers struct fsm_decode *); 651ae349f5Scvs2svn static void CcpLayerStart(struct fsm *); 661ae349f5Scvs2svn static void CcpLayerFinish(struct fsm *); 671ae349f5Scvs2svn static void CcpLayerUp(struct fsm *); 681ae349f5Scvs2svn static void CcpLayerDown(struct fsm *); 691ae349f5Scvs2svn static void CcpInitRestartCounter(struct fsm *); 70503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *); 71503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char); 721ae349f5Scvs2svn 7383d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = { 7483d1af55SBrian Somers CcpLayerUp, 7583d1af55SBrian Somers CcpLayerDown, 7683d1af55SBrian Somers CcpLayerStart, 776d666775SBrian Somers CcpLayerFinish, 7883d1af55SBrian Somers CcpInitRestartCounter, 7983d1af55SBrian Somers CcpSendConfigReq, 802267893fSBrian Somers CcpSentTerminateReq, 8183d1af55SBrian Somers CcpSendTerminateAck, 82503a7782SBrian Somers CcpDecodeConfig, 83503a7782SBrian Somers CcpRecvResetReq, 84503a7782SBrian Somers CcpRecvResetAck 8583d1af55SBrian Somers }; 8683d1af55SBrian Somers 871ae349f5Scvs2svn static char const *cftypes[] = { 881ae349f5Scvs2svn /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 891ae349f5Scvs2svn "OUI", /* 0: OUI */ 901ae349f5Scvs2svn "PRED1", /* 1: Predictor type 1 */ 911ae349f5Scvs2svn "PRED2", /* 2: Predictor type 2 */ 921ae349f5Scvs2svn "PUDDLE", /* 3: Puddle Jumber */ 931ae349f5Scvs2svn "???", "???", "???", "???", "???", "???", 941ae349f5Scvs2svn "???", "???", "???", "???", "???", "???", 951ae349f5Scvs2svn "HWPPC", /* 16: Hewlett-Packard PPC */ 961ae349f5Scvs2svn "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 978f2e5827SBrian Somers "MPPC", /* 18: Microsoft PPC (rfc2118) */ 981ae349f5Scvs2svn "GAND", /* 19: Gandalf FZA (rfc1993) */ 991ae349f5Scvs2svn "V42BIS", /* 20: ARG->DATA.42bis compression */ 1001ae349f5Scvs2svn "BSD", /* 21: BSD LZW Compress */ 1011ae349f5Scvs2svn "???", 1021ae349f5Scvs2svn "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 1031ae349f5Scvs2svn "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 1041342caedSBrian Somers /* 24: Deflate (according to pppd-2.3.*) */ 1051ae349f5Scvs2svn "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 1061ae349f5Scvs2svn "DEFLATE", /* 26: Deflate (rfc1979) */ 1071ae349f5Scvs2svn }; 1081ae349f5Scvs2svn 1091ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 1101ae349f5Scvs2svn 1111ae349f5Scvs2svn static const char * 1121ae349f5Scvs2svn protoname(int proto) 1131ae349f5Scvs2svn { 1141ae349f5Scvs2svn if (proto < 0 || proto > NCFTYPES) 1151ae349f5Scvs2svn return "none"; 1161ae349f5Scvs2svn return cftypes[proto]; 1171ae349f5Scvs2svn } 1181ae349f5Scvs2svn 1191ae349f5Scvs2svn /* We support these algorithms, and Req them in the given order */ 1201ae349f5Scvs2svn static const struct ccp_algorithm *algorithm[] = { 1211ae349f5Scvs2svn &DeflateAlgorithm, 1221ae349f5Scvs2svn &Pred1Algorithm, 1231ae349f5Scvs2svn &PppdDeflateAlgorithm 1241ae349f5Scvs2svn }; 1251ae349f5Scvs2svn 1261ae349f5Scvs2svn #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 1271ae349f5Scvs2svn 1281ae349f5Scvs2svn int 129503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg) 1301ae349f5Scvs2svn { 131cd9647a1SBrian Somers struct link *l = ChooseLink(arg); 132cd9647a1SBrian Somers struct ccp *ccp = &l->ccp; 133503a7782SBrian Somers 134b6217683SBrian Somers prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, 1351e991daaSBrian Somers State2Nam(ccp->fsm.state)); 136b6217683SBrian Somers prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", 137503a7782SBrian Somers protoname(ccp->my_proto), protoname(ccp->his_proto)); 138b6217683SBrian Somers prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", 139503a7782SBrian Somers ccp->uncompout, ccp->compout, 140503a7782SBrian Somers ccp->compin, ccp->uncompin); 141cd9647a1SBrian Somers 142b6217683SBrian Somers prompt_Printf(arg->prompt, "\n Defaults: "); 1431342caedSBrian Somers prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry); 144b6217683SBrian Somers prompt_Printf(arg->prompt, " deflate windows: "); 145b6217683SBrian Somers prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); 146b6217683SBrian Somers prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); 1471342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE: %s\n", 1481342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); 1491342caedSBrian Somers prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", 1501342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); 1511342caedSBrian Somers prompt_Printf(arg->prompt, " DEFLATE24: %s\n", 1521342caedSBrian Somers command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); 1531ae349f5Scvs2svn return 0; 1541ae349f5Scvs2svn } 1551ae349f5Scvs2svn 1561ae349f5Scvs2svn void 1576d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, 1586d666775SBrian Somers const struct fsm_parent *parent) 1591ae349f5Scvs2svn { 1607308ec68SBrian Somers /* Initialise ourselves */ 1613b0f8d2eSBrian Somers static const char *timer_names[] = 1623b0f8d2eSBrian Somers {"CCP restart", "CCP openmode", "CCP stopped"}; 1633b0f8d2eSBrian Somers 1643b0f8d2eSBrian Somers fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP, 1653b0f8d2eSBrian Somers bundle, l, parent, &ccp_Callbacks, timer_names); 166cd9647a1SBrian Somers 16703036ec7SBrian Somers ccp->cfg.deflate.in.winsize = 0; 16803036ec7SBrian Somers ccp->cfg.deflate.out.winsize = 15; 169cd9647a1SBrian Somers ccp->cfg.fsmretry = DEF_FSMRETRY; 1701342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; 1711342caedSBrian Somers ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; 1721342caedSBrian Somers ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; 173cd9647a1SBrian Somers 174503a7782SBrian Somers ccp_Setup(ccp); 175503a7782SBrian Somers } 176503a7782SBrian Somers 177503a7782SBrian Somers void 178503a7782SBrian Somers ccp_Setup(struct ccp *ccp) 179503a7782SBrian Somers { 180503a7782SBrian Somers /* Set ourselves up for a startup */ 181503a7782SBrian Somers ccp->fsm.open_mode = 0; 1825454ccd9SBrian Somers ccp->fsm.maxconfig = 10; 183503a7782SBrian Somers ccp->his_proto = ccp->my_proto = -1; 184503a7782SBrian Somers ccp->reset_sent = ccp->last_reset = -1; 18503036ec7SBrian Somers ccp->in.algorithm = ccp->out.algorithm = -1; 18603036ec7SBrian Somers ccp->in.state = ccp->out.state = NULL; 18703036ec7SBrian Somers ccp->in.opt.id = -1; 18803036ec7SBrian Somers ccp->out.opt = NULL; 189503a7782SBrian Somers ccp->his_reject = ccp->my_reject = 0; 190503a7782SBrian Somers ccp->uncompout = ccp->compout = 0; 191503a7782SBrian Somers ccp->uncompin = ccp->compin = 0; 1921ae349f5Scvs2svn } 1931ae349f5Scvs2svn 1941ae349f5Scvs2svn static void 1951ae349f5Scvs2svn CcpInitRestartCounter(struct fsm *fp) 1961ae349f5Scvs2svn { 1977308ec68SBrian Somers /* Set fsm timer load */ 198cd9647a1SBrian Somers struct ccp *ccp = fsm2ccp(fp); 199cd9647a1SBrian Somers 200cd9647a1SBrian Somers fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS; 2011ae349f5Scvs2svn fp->restart = 5; 2021ae349f5Scvs2svn } 2031ae349f5Scvs2svn 2041ae349f5Scvs2svn static void 2051ae349f5Scvs2svn CcpSendConfigReq(struct fsm *fp) 2061ae349f5Scvs2svn { 2077308ec68SBrian Somers /* Send config REQ please */ 208aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 20903036ec7SBrian Somers struct ccp_opt **o; 21030c2f2ffSBrian Somers u_char *cp, buff[100]; 21103036ec7SBrian Somers int f, alloc; 2121ae349f5Scvs2svn 21330c2f2ffSBrian Somers cp = buff; 21403036ec7SBrian Somers o = &ccp->out.opt; 21503036ec7SBrian Somers alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; 21683d1af55SBrian Somers ccp->my_proto = -1; 21703036ec7SBrian Somers ccp->out.algorithm = -1; 2181ae349f5Scvs2svn for (f = 0; f < NALGORITHMS; f++) 2191342caedSBrian Somers if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && 2201342caedSBrian Somers !REJECTED(ccp, algorithm[f]->id)) { 221ba081e43SBrian Somers 222ba081e43SBrian Somers if (!alloc) 223ba081e43SBrian Somers for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) 224ba081e43SBrian Somers if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) 225ba081e43SBrian Somers break; 226ba081e43SBrian Somers 227ba081e43SBrian Somers if (alloc || *o == NULL) { 22803036ec7SBrian Somers *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); 22903036ec7SBrian Somers (*o)->val.id = algorithm[f]->id; 23003036ec7SBrian Somers (*o)->val.len = 2; 23103036ec7SBrian Somers (*o)->next = NULL; 23203036ec7SBrian Somers (*o)->algorithm = f; 23303036ec7SBrian Somers (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); 23403036ec7SBrian Somers } 2351ae349f5Scvs2svn 23603036ec7SBrian Somers if (cp + (*o)->val.len > buff + sizeof buff) { 237d47dceb8SBrian Somers LogPrintf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); 23830c2f2ffSBrian Somers break; 23930c2f2ffSBrian Somers } 2402267893fSBrian Somers memcpy(cp, &(*o)->val, (*o)->val.len); 2412267893fSBrian Somers cp += (*o)->val.len; 24203036ec7SBrian Somers 24303036ec7SBrian Somers ccp->my_proto = (*o)->val.id; 24403036ec7SBrian Somers ccp->out.algorithm = f; 24503036ec7SBrian Somers 24603036ec7SBrian Somers if (alloc) 24703036ec7SBrian Somers o = &(*o)->next; 2481ae349f5Scvs2svn } 2492267893fSBrian Somers 2502267893fSBrian Somers FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff); 2511ae349f5Scvs2svn } 2521ae349f5Scvs2svn 2531ae349f5Scvs2svn void 2541ae349f5Scvs2svn CcpSendResetReq(struct fsm *fp) 2551ae349f5Scvs2svn { 2567308ec68SBrian Somers /* We can't read our input - ask peer to reset */ 257aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 2582267893fSBrian Somers 25983d1af55SBrian Somers ccp->reset_sent = fp->reqid; 26083d1af55SBrian Somers ccp->last_reset = -1; 2611ae349f5Scvs2svn FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0); 2621ae349f5Scvs2svn } 2631ae349f5Scvs2svn 2641ae349f5Scvs2svn static void 2652267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp) 2661ae349f5Scvs2svn { 2677308ec68SBrian Somers /* Term REQ just sent by FSM */ 2681ae349f5Scvs2svn } 2691ae349f5Scvs2svn 2701ae349f5Scvs2svn static void 2712267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id) 2721ae349f5Scvs2svn { 2737308ec68SBrian Somers /* Send Term ACK please */ 2742267893fSBrian Somers FsmOutput(fp, CODE_TERMACK, id, NULL, 0); 2751ae349f5Scvs2svn } 2761ae349f5Scvs2svn 277503a7782SBrian Somers static void 2781ae349f5Scvs2svn CcpRecvResetReq(struct fsm *fp) 2791ae349f5Scvs2svn { 2807308ec68SBrian Somers /* Got a reset REQ, reset outgoing dictionary */ 281aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 28203036ec7SBrian Somers if (ccp->out.state != NULL) 28303036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); 2841ae349f5Scvs2svn } 2851ae349f5Scvs2svn 2861ae349f5Scvs2svn static void 2871ae349f5Scvs2svn CcpLayerStart(struct fsm *fp) 2881ae349f5Scvs2svn { 2897308ec68SBrian Somers /* We're about to start up ! */ 290d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: CcpLayerStart.\n", fp->link->name); 2911ae349f5Scvs2svn } 2921ae349f5Scvs2svn 2931ae349f5Scvs2svn static void 2941ae349f5Scvs2svn CcpLayerFinish(struct fsm *fp) 2951ae349f5Scvs2svn { 2967308ec68SBrian Somers /* We're now down */ 297aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 298ba081e43SBrian Somers struct ccp_opt *next; 299ba081e43SBrian Somers 300d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: CcpLayerFinish.\n", fp->link->name); 30103036ec7SBrian Somers if (ccp->in.state != NULL) { 30203036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); 30303036ec7SBrian Somers ccp->in.state = NULL; 3048d9b9867SBrian Somers ccp->in.algorithm = -1; 3057308ec68SBrian Somers } 30603036ec7SBrian Somers if (ccp->out.state != NULL) { 30703036ec7SBrian Somers (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); 30803036ec7SBrian Somers ccp->out.state = NULL; 3098d9b9867SBrian Somers ccp->out.algorithm = -1; 3107308ec68SBrian Somers } 3118d9b9867SBrian Somers ccp->his_reject = ccp->my_reject = 0; 312ba081e43SBrian Somers 313ba081e43SBrian Somers while (ccp->out.opt) { 314ba081e43SBrian Somers next = ccp->out.opt->next; 315ba081e43SBrian Somers free(ccp->out.opt); 316ba081e43SBrian Somers ccp->out.opt = next; 317ba081e43SBrian Somers } 3181ae349f5Scvs2svn } 3191ae349f5Scvs2svn 3201ae349f5Scvs2svn static void 3211ae349f5Scvs2svn CcpLayerDown(struct fsm *fp) 3221ae349f5Scvs2svn { 3237308ec68SBrian Somers /* About to come down */ 324d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: CcpLayerDown.\n", fp->link->name); 3251ae349f5Scvs2svn } 3261ae349f5Scvs2svn 3271ae349f5Scvs2svn /* 3281ae349f5Scvs2svn * Called when CCP has reached the OPEN state 3291ae349f5Scvs2svn */ 3301ae349f5Scvs2svn static void 3311ae349f5Scvs2svn CcpLayerUp(struct fsm *fp) 3321ae349f5Scvs2svn { 3337308ec68SBrian Somers /* We're now up */ 334aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 335d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: CcpLayerUp.\n", fp->link->name); 33603036ec7SBrian Somers if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 33703036ec7SBrian Somers ccp->in.algorithm < NALGORITHMS) { 33803036ec7SBrian Somers ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 33903036ec7SBrian Somers if (ccp->in.state == NULL) { 340d47dceb8SBrian Somers LogPrintf(LogERROR, "%s: %s (in) initialisation failure\n", 341d47dceb8SBrian Somers fp->link->name, protoname(ccp->his_proto)); 34283d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 343247ab36dSBrian Somers FsmClose(fp); 344247ab36dSBrian Somers } 34503036ec7SBrian Somers } 34603036ec7SBrian Somers 34703036ec7SBrian Somers if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 34803036ec7SBrian Somers ccp->out.algorithm < NALGORITHMS) { 34903036ec7SBrian Somers ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) 35003036ec7SBrian Somers (&ccp->out.opt->val); 35103036ec7SBrian Somers if (ccp->out.state == NULL) { 352d47dceb8SBrian Somers LogPrintf(LogERROR, "%s: %s (out) initialisation failure\n", 353d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto)); 35483d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 355247ab36dSBrian Somers FsmClose(fp); 356247ab36dSBrian Somers } 35703036ec7SBrian Somers } 35803036ec7SBrian Somers 359d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 360d47dceb8SBrian Somers fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 36183d1af55SBrian Somers protoname(ccp->his_proto), ccp->his_proto); 3621ae349f5Scvs2svn } 3631ae349f5Scvs2svn 3641ae349f5Scvs2svn static void 36530c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 36630c2f2ffSBrian Somers struct fsm_decode *dec) 3671ae349f5Scvs2svn { 3687308ec68SBrian Somers /* Deal with incoming data */ 369aad81d1eSBrian Somers struct ccp *ccp = fsm2ccp(fp); 3701ae349f5Scvs2svn int type, length; 3711ae349f5Scvs2svn int f; 37203036ec7SBrian Somers const char *end; 3731ae349f5Scvs2svn 3741ae349f5Scvs2svn while (plen >= sizeof(struct fsmconfig)) { 3751ae349f5Scvs2svn type = *cp; 3761ae349f5Scvs2svn length = cp[1]; 37703036ec7SBrian Somers 378d47dceb8SBrian Somers if (length == 0) { 379d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: CCP size zero\n", fp->link->name); 380d47dceb8SBrian Somers break; 381d47dceb8SBrian Somers } 382d47dceb8SBrian Somers 38303036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 38403036ec7SBrian Somers length = sizeof(struct lcp_opt); 385d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: Warning: Truncating length to %d\n", 386d47dceb8SBrian Somers fp->link->name, length); 38703036ec7SBrian Somers } 3881ae349f5Scvs2svn 3891ae349f5Scvs2svn for (f = NALGORITHMS-1; f > -1; f--) 3901ae349f5Scvs2svn if (algorithm[f]->id == type) 3911ae349f5Scvs2svn break; 3921ae349f5Scvs2svn 39303036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 39403036ec7SBrian Somers if (end == NULL) 39503036ec7SBrian Somers end = ""; 39603036ec7SBrian Somers 39703036ec7SBrian Somers if (type < NCFTYPES) 39803036ec7SBrian Somers LogPrintf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); 39903036ec7SBrian Somers else 40003036ec7SBrian Somers LogPrintf(LogCCP, " ???[%d] %s\n", length, end); 40103036ec7SBrian Somers 4021ae349f5Scvs2svn if (f == -1) { 4031ae349f5Scvs2svn /* Don't understand that :-( */ 4041ae349f5Scvs2svn if (mode_type == MODE_REQ) { 40583d1af55SBrian Somers ccp->my_reject |= (1 << type); 40630c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 40730c2f2ffSBrian Somers dec->rejend += length; 4081ae349f5Scvs2svn } 4091ae349f5Scvs2svn } else { 41003036ec7SBrian Somers struct ccp_opt *o; 4111ae349f5Scvs2svn 4121ae349f5Scvs2svn switch (mode_type) { 4131ae349f5Scvs2svn case MODE_REQ: 4141342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 4151342caedSBrian Somers ccp->in.algorithm == -1) { 41603036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 41703036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 4181ae349f5Scvs2svn case MODE_REJ: 41903036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 42003036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 4211ae349f5Scvs2svn break; 4221ae349f5Scvs2svn case MODE_NAK: 42303036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 42403036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 4251ae349f5Scvs2svn break; 4261ae349f5Scvs2svn case MODE_ACK: 42730c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 42830c2f2ffSBrian Somers dec->ackend += length; 42983d1af55SBrian Somers ccp->his_proto = type; 43003036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 4311ae349f5Scvs2svn break; 4321ae349f5Scvs2svn } 4331ae349f5Scvs2svn } else { 43430c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 43530c2f2ffSBrian Somers dec->rejend += length; 4361ae349f5Scvs2svn } 4371ae349f5Scvs2svn break; 4381ae349f5Scvs2svn case MODE_NAK: 43903036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 44003036ec7SBrian Somers if (o->val.id == cp[0]) 44103036ec7SBrian Somers break; 44203036ec7SBrian Somers if (o == NULL) 443d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n", 444d47dceb8SBrian Somers fp->link->name); 44503036ec7SBrian Somers else { 44603036ec7SBrian Somers memcpy(&o->val, cp, length); 44703036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 44883d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 4491ae349f5Scvs2svn else { 45083d1af55SBrian Somers ccp->his_reject |= (1 << type); 45183d1af55SBrian Somers ccp->my_proto = -1; 4521ae349f5Scvs2svn } 45303036ec7SBrian Somers } 4541ae349f5Scvs2svn break; 4551ae349f5Scvs2svn case MODE_REJ: 45683d1af55SBrian Somers ccp->his_reject |= (1 << type); 45783d1af55SBrian Somers ccp->my_proto = -1; 4581ae349f5Scvs2svn break; 4591ae349f5Scvs2svn } 4601ae349f5Scvs2svn } 4611ae349f5Scvs2svn 46203036ec7SBrian Somers plen -= cp[1]; 46303036ec7SBrian Somers cp += cp[1]; 4641ae349f5Scvs2svn } 4651ae349f5Scvs2svn 466e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 4671342caedSBrian Somers if (dec->rejend != dec->rej) { 46803036ec7SBrian Somers /* rejects are preferred */ 46903036ec7SBrian Somers dec->ackend = dec->ack; 47003036ec7SBrian Somers dec->nakend = dec->nak; 47103036ec7SBrian Somers if (ccp->in.state == NULL) { 47283d1af55SBrian Somers ccp->his_proto = -1; 47303036ec7SBrian Somers ccp->in.algorithm = -1; 47403036ec7SBrian Somers } 4751342caedSBrian Somers } else if (dec->nakend != dec->nak) { 47603036ec7SBrian Somers /* then NAKs */ 47703036ec7SBrian Somers dec->ackend = dec->ack; 47803036ec7SBrian Somers if (ccp->in.state == NULL) { 47903036ec7SBrian Somers ccp->his_proto = -1; 48003036ec7SBrian Somers ccp->in.algorithm = -1; 481247ab36dSBrian Somers } 4821ae349f5Scvs2svn } 4831ae349f5Scvs2svn } 484e43ebac1SBrian Somers } 4851ae349f5Scvs2svn 4861ae349f5Scvs2svn void 487f4768038SBrian Somers CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) 4881ae349f5Scvs2svn { 4897308ec68SBrian Somers /* Got PROTO_CCP from link */ 490455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 491f4768038SBrian Somers FsmInput(&ccp->fsm, bp); 492455aabc3SBrian Somers else if (bundle_Phase(bundle) < PHASE_NETWORK) { 493d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 494d47dceb8SBrian Somers ccp->fsm.link->name, bundle_PhaseName(bundle)); 4951ae349f5Scvs2svn pfree(bp); 4961ae349f5Scvs2svn } 4971ae349f5Scvs2svn } 4981ae349f5Scvs2svn 499503a7782SBrian Somers static void 500503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 5011ae349f5Scvs2svn { 5027308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 503f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 504f4768038SBrian Somers 505f4768038SBrian Somers if (ccp->reset_sent != -1) { 506f4768038SBrian Somers if (id != ccp->reset_sent) { 507d47dceb8SBrian Somers LogPrintf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)" 508d47dceb8SBrian Somers " ignored\n", fp->link->name, id, ccp->reset_sent); 5091ae349f5Scvs2svn return; 5101ae349f5Scvs2svn } 5111ae349f5Scvs2svn /* Whaddaya know - a correct reset ack */ 512f4768038SBrian Somers } else if (id == ccp->last_reset) 513d47dceb8SBrian Somers LogPrintf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 514d47dceb8SBrian Somers fp->link->name); 5151ae349f5Scvs2svn else { 516d47dceb8SBrian Somers LogPrintf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n", 517d47dceb8SBrian Somers fp->link->name, id); 5181ae349f5Scvs2svn return; 5191ae349f5Scvs2svn } 5201ae349f5Scvs2svn 521f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 522f4768038SBrian Somers ccp->reset_sent = -1; 52303036ec7SBrian Somers if (ccp->in.state != NULL) 52403036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 5251ae349f5Scvs2svn } 5261ae349f5Scvs2svn 5271ae349f5Scvs2svn int 5283b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto, 529503a7782SBrian Somers struct mbuf *m) 5301ae349f5Scvs2svn { 531503a7782SBrian Somers /* Compress outgoing Network Layer data */ 53203036ec7SBrian Somers if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED && 53303036ec7SBrian Somers ccp->out.state != NULL) 53403036ec7SBrian Somers return (*algorithm[ccp->out.algorithm]->o.Write) 53503036ec7SBrian Somers (ccp->out.state, ccp, l, pri, proto, m); 5361ae349f5Scvs2svn return 0; 5371ae349f5Scvs2svn } 5381ae349f5Scvs2svn 5391ae349f5Scvs2svn struct mbuf * 540503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) 5411ae349f5Scvs2svn { 542ee6c193fSBrian Somers /* 543ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 544ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 545ee6c193fSBrian Somers */ 546e43ebac1SBrian Somers if (ccp->fsm.state == ST_OPENED) { 547ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 5487308ec68SBrian Somers /* Decompress incoming data */ 5492267893fSBrian Somers if (ccp->reset_sent != -1) 5501ae349f5Scvs2svn /* Send another REQ and put the packet in the bit bucket */ 551503a7782SBrian Somers FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); 5522267893fSBrian Somers else if (ccp->in.state != NULL) 55303036ec7SBrian Somers return (*algorithm[ccp->in.algorithm]->i.Read) 55403036ec7SBrian Somers (ccp->in.state, ccp, proto, bp); 555ee6c193fSBrian Somers pfree(bp); 556ee6c193fSBrian Somers bp = NULL; 55703036ec7SBrian Somers } else if ((*proto & 0xfff1) == 0x21 && ccp->in.state != NULL) 558ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 55903036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.DictSetup) 56003036ec7SBrian Somers (ccp->in.state, ccp, *proto, bp); 561e43ebac1SBrian Somers } 5621ae349f5Scvs2svn 563ee6c193fSBrian Somers return bp; 5641ae349f5Scvs2svn } 565ed32233cSBrian Somers 566ed32233cSBrian Somers u_short 567ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 568ed32233cSBrian Somers { 569ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 570ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 571ed32233cSBrian Somers } 572