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 * 20ed32233cSBrian Somers * $Id: ccp.c,v 1.30.2.36 1998/04/19 03:40:54 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) { 23730c2f2ffSBrian Somers LogPrintf(LogERROR, "CCP REQ buffer overrun !\n"); 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 ! */ 2901ae349f5Scvs2svn LogPrintf(LogCCP, "CcpLayerStart.\n"); 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 3001ae349f5Scvs2svn LogPrintf(LogCCP, "CcpLayerFinish.\n"); 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 */ 3241ae349f5Scvs2svn LogPrintf(LogCCP, "CcpLayerDown.\n"); 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); 335455aabc3SBrian Somers LogPrintf(LogCCP, "CcpLayerUp.\n"); 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) { 340247ab36dSBrian Somers LogPrintf(LogERROR, "%s (in) initialisation failure\n", 34183d1af55SBrian Somers 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) { 352247ab36dSBrian Somers LogPrintf(LogERROR, "%s (out) initialisation failure\n", 35383d1af55SBrian Somers protoname(ccp->my_proto)); 35483d1af55SBrian Somers ccp->his_proto = ccp->my_proto = -1; 355247ab36dSBrian Somers FsmClose(fp); 356247ab36dSBrian Somers } 35703036ec7SBrian Somers } 35803036ec7SBrian Somers 3591ae349f5Scvs2svn LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n", 36083d1af55SBrian Somers 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 37803036ec7SBrian Somers if (length > sizeof(struct lcp_opt)) { 37903036ec7SBrian Somers length = sizeof(struct lcp_opt); 38003036ec7SBrian Somers LogPrintf(LogCCP, "Warning: Truncating length to %d\n", length); 38103036ec7SBrian Somers } 3821ae349f5Scvs2svn 3831ae349f5Scvs2svn for (f = NALGORITHMS-1; f > -1; f--) 3841ae349f5Scvs2svn if (algorithm[f]->id == type) 3851ae349f5Scvs2svn break; 3861ae349f5Scvs2svn 38703036ec7SBrian Somers end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 38803036ec7SBrian Somers if (end == NULL) 38903036ec7SBrian Somers end = ""; 39003036ec7SBrian Somers 39103036ec7SBrian Somers if (type < NCFTYPES) 39203036ec7SBrian Somers LogPrintf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); 39303036ec7SBrian Somers else 39403036ec7SBrian Somers LogPrintf(LogCCP, " ???[%d] %s\n", length, end); 39503036ec7SBrian Somers 3961ae349f5Scvs2svn if (f == -1) { 3971ae349f5Scvs2svn /* Don't understand that :-( */ 3981ae349f5Scvs2svn if (mode_type == MODE_REQ) { 39983d1af55SBrian Somers ccp->my_reject |= (1 << type); 40030c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 40130c2f2ffSBrian Somers dec->rejend += length; 4021ae349f5Scvs2svn } 4031ae349f5Scvs2svn } else { 40403036ec7SBrian Somers struct ccp_opt *o; 4051ae349f5Scvs2svn 4061ae349f5Scvs2svn switch (mode_type) { 4071ae349f5Scvs2svn case MODE_REQ: 4081342caedSBrian Somers if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 4091342caedSBrian Somers ccp->in.algorithm == -1) { 41003036ec7SBrian Somers memcpy(&ccp->in.opt, cp, length); 41103036ec7SBrian Somers switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 4121ae349f5Scvs2svn case MODE_REJ: 41303036ec7SBrian Somers memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 41403036ec7SBrian Somers dec->rejend += ccp->in.opt.len; 4151ae349f5Scvs2svn break; 4161ae349f5Scvs2svn case MODE_NAK: 41703036ec7SBrian Somers memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 41803036ec7SBrian Somers dec->nakend += ccp->in.opt.len; 4191ae349f5Scvs2svn break; 4201ae349f5Scvs2svn case MODE_ACK: 42130c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 42230c2f2ffSBrian Somers dec->ackend += length; 42383d1af55SBrian Somers ccp->his_proto = type; 42403036ec7SBrian Somers ccp->in.algorithm = f; /* This one'll do :-) */ 4251ae349f5Scvs2svn break; 4261ae349f5Scvs2svn } 4271ae349f5Scvs2svn } else { 42830c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 42930c2f2ffSBrian Somers dec->rejend += length; 4301ae349f5Scvs2svn } 4311ae349f5Scvs2svn break; 4321ae349f5Scvs2svn case MODE_NAK: 43303036ec7SBrian Somers for (o = ccp->out.opt; o != NULL; o = o->next) 43403036ec7SBrian Somers if (o->val.id == cp[0]) 43503036ec7SBrian Somers break; 43603036ec7SBrian Somers if (o == NULL) 43703036ec7SBrian Somers LogPrintf(LogCCP, "Warning: Ignoring peer NAK of unsent option\n"); 43803036ec7SBrian Somers else { 43903036ec7SBrian Somers memcpy(&o->val, cp, length); 44003036ec7SBrian Somers if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 44183d1af55SBrian Somers ccp->my_proto = algorithm[f]->id; 4421ae349f5Scvs2svn else { 44383d1af55SBrian Somers ccp->his_reject |= (1 << type); 44483d1af55SBrian Somers ccp->my_proto = -1; 4451ae349f5Scvs2svn } 44603036ec7SBrian Somers } 4471ae349f5Scvs2svn break; 4481ae349f5Scvs2svn case MODE_REJ: 44983d1af55SBrian Somers ccp->his_reject |= (1 << type); 45083d1af55SBrian Somers ccp->my_proto = -1; 4511ae349f5Scvs2svn break; 4521ae349f5Scvs2svn } 4531ae349f5Scvs2svn } 4541ae349f5Scvs2svn 45503036ec7SBrian Somers plen -= cp[1]; 45603036ec7SBrian Somers cp += cp[1]; 4571ae349f5Scvs2svn } 4581ae349f5Scvs2svn 4591342caedSBrian Somers if (mode_type != MODE_NOP) 4601342caedSBrian Somers if (dec->rejend != dec->rej) { 46103036ec7SBrian Somers /* rejects are preferred */ 46203036ec7SBrian Somers dec->ackend = dec->ack; 46303036ec7SBrian Somers dec->nakend = dec->nak; 46403036ec7SBrian Somers if (ccp->in.state == NULL) { 46583d1af55SBrian Somers ccp->his_proto = -1; 46603036ec7SBrian Somers ccp->in.algorithm = -1; 46703036ec7SBrian Somers } 4681342caedSBrian Somers } else if (dec->nakend != dec->nak) { 46903036ec7SBrian Somers /* then NAKs */ 47003036ec7SBrian Somers dec->ackend = dec->ack; 47103036ec7SBrian Somers if (ccp->in.state == NULL) { 47203036ec7SBrian Somers ccp->his_proto = -1; 47303036ec7SBrian Somers ccp->in.algorithm = -1; 474247ab36dSBrian Somers } 4751ae349f5Scvs2svn } 4761ae349f5Scvs2svn } 4771ae349f5Scvs2svn 4781ae349f5Scvs2svn void 479f4768038SBrian Somers CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) 4801ae349f5Scvs2svn { 4817308ec68SBrian Somers /* Got PROTO_CCP from link */ 482455aabc3SBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 483f4768038SBrian Somers FsmInput(&ccp->fsm, bp); 484455aabc3SBrian Somers else if (bundle_Phase(bundle) < PHASE_NETWORK) { 485455aabc3SBrian Somers LogPrintf(LogCCP, "Error: Unexpected CCP in phase %s (ignored)\n", 486455aabc3SBrian Somers bundle_PhaseName(bundle)); 4871ae349f5Scvs2svn pfree(bp); 4881ae349f5Scvs2svn } 4891ae349f5Scvs2svn } 4901ae349f5Scvs2svn 491503a7782SBrian Somers static void 492503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id) 4931ae349f5Scvs2svn { 4947308ec68SBrian Somers /* Got a reset ACK, reset incoming dictionary */ 495f4768038SBrian Somers struct ccp *ccp = fsm2ccp(fp); 496f4768038SBrian Somers 497f4768038SBrian Somers if (ccp->reset_sent != -1) { 498f4768038SBrian Somers if (id != ccp->reset_sent) { 4991ae349f5Scvs2svn LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n", 500f4768038SBrian Somers id, ccp->reset_sent); 5011ae349f5Scvs2svn return; 5021ae349f5Scvs2svn } 5031ae349f5Scvs2svn /* Whaddaya know - a correct reset ack */ 504f4768038SBrian Somers } else if (id == ccp->last_reset) 5051ae349f5Scvs2svn LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n"); 5061ae349f5Scvs2svn else { 5071ae349f5Scvs2svn LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id); 5081ae349f5Scvs2svn return; 5091ae349f5Scvs2svn } 5101ae349f5Scvs2svn 511f4768038SBrian Somers ccp->last_reset = ccp->reset_sent; 512f4768038SBrian Somers ccp->reset_sent = -1; 51303036ec7SBrian Somers if (ccp->in.state != NULL) 51403036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 5151ae349f5Scvs2svn } 5161ae349f5Scvs2svn 5171ae349f5Scvs2svn int 5183b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto, 519503a7782SBrian Somers struct mbuf *m) 5201ae349f5Scvs2svn { 521503a7782SBrian Somers /* Compress outgoing Network Layer data */ 52203036ec7SBrian Somers if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED && 52303036ec7SBrian Somers ccp->out.state != NULL) 52403036ec7SBrian Somers return (*algorithm[ccp->out.algorithm]->o.Write) 52503036ec7SBrian Somers (ccp->out.state, ccp, l, pri, proto, m); 5261ae349f5Scvs2svn return 0; 5271ae349f5Scvs2svn } 5281ae349f5Scvs2svn 5291ae349f5Scvs2svn struct mbuf * 530503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) 5311ae349f5Scvs2svn { 532ee6c193fSBrian Somers /* 533ed32233cSBrian Somers * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 534ee6c193fSBrian Somers * decompression routines so that the dictionary's updated 535ee6c193fSBrian Somers */ 536503a7782SBrian Somers if (ccp->fsm.state == ST_OPENED) 537ed32233cSBrian Somers if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 5387308ec68SBrian Somers /* Decompress incoming data */ 5392267893fSBrian Somers if (ccp->reset_sent != -1) 5401ae349f5Scvs2svn /* Send another REQ and put the packet in the bit bucket */ 541503a7782SBrian Somers FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); 5422267893fSBrian Somers else if (ccp->in.state != NULL) 54303036ec7SBrian Somers return (*algorithm[ccp->in.algorithm]->i.Read) 54403036ec7SBrian Somers (ccp->in.state, ccp, proto, bp); 545ee6c193fSBrian Somers pfree(bp); 546ee6c193fSBrian Somers bp = NULL; 54703036ec7SBrian Somers } else if ((*proto & 0xfff1) == 0x21 && ccp->in.state != NULL) 548ee6c193fSBrian Somers /* Add incoming Network Layer traffic to our dictionary */ 54903036ec7SBrian Somers (*algorithm[ccp->in.algorithm]->i.DictSetup) 55003036ec7SBrian Somers (ccp->in.state, ccp, *proto, bp); 5511ae349f5Scvs2svn 552ee6c193fSBrian Somers return bp; 5531ae349f5Scvs2svn } 554ed32233cSBrian Somers 555ed32233cSBrian Somers u_short 556ed32233cSBrian Somers ccp_Proto(struct ccp *ccp) 557ed32233cSBrian Somers { 558ed32233cSBrian Somers return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 559ed32233cSBrian Somers PROTO_COMPD : PROTO_ICOMPD; 560ed32233cSBrian Somers } 561