xref: /freebsd/usr.sbin/ppp/ccp.c (revision b6217683dc0269a53b799399522dbdfb5a4919cc)
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  *
20b6217683SBrian Somers  * $Id: ccp.c,v 1.30.2.30 1998/04/03 19:23:53 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o Support other compression protocols
241ae349f5Scvs2svn  */
251ae349f5Scvs2svn #include <sys/param.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>
321ae349f5Scvs2svn #include <string.h>
3385b542cfSBrian Somers #include <termios.h>
341ae349f5Scvs2svn 
351ae349f5Scvs2svn #include "command.h"
361ae349f5Scvs2svn #include "mbuf.h"
371ae349f5Scvs2svn #include "log.h"
381ae349f5Scvs2svn #include "defs.h"
391ae349f5Scvs2svn #include "timer.h"
401ae349f5Scvs2svn #include "fsm.h"
411ae349f5Scvs2svn #include "lcpproto.h"
421ae349f5Scvs2svn #include "lcp.h"
431ae349f5Scvs2svn #include "ccp.h"
441ae349f5Scvs2svn #include "loadalias.h"
451ae349f5Scvs2svn #include "vars.h"
461ae349f5Scvs2svn #include "pred.h"
471ae349f5Scvs2svn #include "deflate.h"
485828db6dSBrian Somers #include "throughput.h"
495828db6dSBrian Somers #include "iplist.h"
50eaa4df37SBrian Somers #include "slcompress.h"
515828db6dSBrian Somers #include "ipcp.h"
525ca5389aSBrian Somers #include "filter.h"
5385b542cfSBrian Somers #include "descriptor.h"
5485b542cfSBrian Somers #include "prompt.h"
55879ed6faSBrian Somers #include "lqr.h"
56503a7782SBrian Somers #include "hdlc.h"
57503a7782SBrian Somers #include "link.h"
583b0f8d2eSBrian Somers #include "mp.h"
593b0f8d2eSBrian Somers #include "bundle.h"
60503a7782SBrian Somers #include "chat.h"
61e2ebb036SBrian Somers #include "auth.h"
62e2ebb036SBrian Somers #include "chap.h"
633b0f8d2eSBrian Somers #include "async.h"
643b0f8d2eSBrian Somers #include "physical.h"
65503a7782SBrian Somers #include "datalink.h"
661ae349f5Scvs2svn 
671ae349f5Scvs2svn static void CcpSendConfigReq(struct fsm *);
682267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
692267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
7030c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
7130c2f2ffSBrian Somers                             struct fsm_decode *);
721ae349f5Scvs2svn static void CcpLayerStart(struct fsm *);
731ae349f5Scvs2svn static void CcpLayerFinish(struct fsm *);
741ae349f5Scvs2svn static void CcpLayerUp(struct fsm *);
751ae349f5Scvs2svn static void CcpLayerDown(struct fsm *);
761ae349f5Scvs2svn static void CcpInitRestartCounter(struct fsm *);
77503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
78503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
791ae349f5Scvs2svn 
8083d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
8183d1af55SBrian Somers   CcpLayerUp,
8283d1af55SBrian Somers   CcpLayerDown,
8383d1af55SBrian Somers   CcpLayerStart,
846d666775SBrian Somers   CcpLayerFinish,
8583d1af55SBrian Somers   CcpInitRestartCounter,
8683d1af55SBrian Somers   CcpSendConfigReq,
872267893fSBrian Somers   CcpSentTerminateReq,
8883d1af55SBrian Somers   CcpSendTerminateAck,
89503a7782SBrian Somers   CcpDecodeConfig,
90503a7782SBrian Somers   CcpRecvResetReq,
91503a7782SBrian Somers   CcpRecvResetAck
9283d1af55SBrian Somers };
9383d1af55SBrian Somers 
941ae349f5Scvs2svn static char const *cftypes[] = {
951ae349f5Scvs2svn   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
961ae349f5Scvs2svn   "OUI",		/* 0: OUI */
971ae349f5Scvs2svn   "PRED1",		/* 1: Predictor type 1 */
981ae349f5Scvs2svn   "PRED2",		/* 2: Predictor type 2 */
991ae349f5Scvs2svn   "PUDDLE",		/* 3: Puddle Jumber */
1001ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
1011ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
1021ae349f5Scvs2svn   "HWPPC",		/* 16: Hewlett-Packard PPC */
1031ae349f5Scvs2svn   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
1048f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
1051ae349f5Scvs2svn   "GAND",		/* 19: Gandalf FZA (rfc1993) */
1061ae349f5Scvs2svn   "V42BIS",		/* 20: ARG->DATA.42bis compression */
1071ae349f5Scvs2svn   "BSD",		/* 21: BSD LZW Compress */
1081ae349f5Scvs2svn   "???",
1091ae349f5Scvs2svn   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1101ae349f5Scvs2svn   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1111ae349f5Scvs2svn 			/* 24: Deflate (according to pppd-2.3.1) */
1121ae349f5Scvs2svn   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1131ae349f5Scvs2svn   "DEFLATE",		/* 26: Deflate (rfc1979) */
1141ae349f5Scvs2svn };
1151ae349f5Scvs2svn 
1161ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1171ae349f5Scvs2svn 
1181ae349f5Scvs2svn static const char *
1191ae349f5Scvs2svn protoname(int proto)
1201ae349f5Scvs2svn {
1211ae349f5Scvs2svn   if (proto < 0 || proto > NCFTYPES)
1221ae349f5Scvs2svn     return "none";
1231ae349f5Scvs2svn   return cftypes[proto];
1241ae349f5Scvs2svn }
1251ae349f5Scvs2svn 
1261ae349f5Scvs2svn /* We support these algorithms, and Req them in the given order */
1271ae349f5Scvs2svn static const struct ccp_algorithm *algorithm[] = {
1281ae349f5Scvs2svn   &DeflateAlgorithm,
1291ae349f5Scvs2svn   &Pred1Algorithm,
1301ae349f5Scvs2svn   &PppdDeflateAlgorithm
1311ae349f5Scvs2svn };
1321ae349f5Scvs2svn 
1331ae349f5Scvs2svn #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1341ae349f5Scvs2svn 
1351ae349f5Scvs2svn int
136503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
1371ae349f5Scvs2svn {
138cd9647a1SBrian Somers   struct link *l = ChooseLink(arg);
139cd9647a1SBrian Somers   struct ccp *ccp = &l->ccp;
140503a7782SBrian Somers 
141b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1421e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
143b6217683SBrian Somers   prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
144503a7782SBrian Somers                 protoname(ccp->my_proto), protoname(ccp->his_proto));
145b6217683SBrian Somers   prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
146503a7782SBrian Somers                 ccp->uncompout, ccp->compout,
147503a7782SBrian Somers                 ccp->compin, ccp->uncompin);
148cd9647a1SBrian Somers 
149b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
150b6217683SBrian Somers   prompt_Printf(arg->prompt, "deflate windows: ");
151b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
152b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
153b6217683SBrian Somers   prompt_Printf(arg->prompt, "           FSM retry = %us\n", ccp->cfg.fsmretry);
1541ae349f5Scvs2svn   return 0;
1551ae349f5Scvs2svn }
1561ae349f5Scvs2svn 
1571ae349f5Scvs2svn void
1586d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1596d666775SBrian Somers          const struct fsm_parent *parent)
1601ae349f5Scvs2svn {
1617308ec68SBrian Somers   /* Initialise ourselves */
1623b0f8d2eSBrian Somers   static const char *timer_names[] =
1633b0f8d2eSBrian Somers     {"CCP restart", "CCP openmode", "CCP stopped"};
1643b0f8d2eSBrian Somers 
1653b0f8d2eSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
1663b0f8d2eSBrian Somers            bundle, l, parent, &ccp_Callbacks, timer_names);
167cd9647a1SBrian Somers 
16803036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
16903036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
170cd9647a1SBrian Somers   ccp->cfg.fsmretry = DEF_FSMRETRY;
171cd9647a1SBrian Somers 
172503a7782SBrian Somers   ccp_Setup(ccp);
173503a7782SBrian Somers }
174503a7782SBrian Somers 
175503a7782SBrian Somers void
176503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
177503a7782SBrian Somers {
178503a7782SBrian Somers   /* Set ourselves up for a startup */
179503a7782SBrian Somers   ccp->fsm.open_mode = 0;
1805454ccd9SBrian Somers   ccp->fsm.maxconfig = 10;
181503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
182503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
18303036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
18403036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
18503036ec7SBrian Somers   ccp->in.opt.id = -1;
18603036ec7SBrian Somers   ccp->out.opt = NULL;
187503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
188503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
189503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
1901ae349f5Scvs2svn }
1911ae349f5Scvs2svn 
1921ae349f5Scvs2svn static void
1931ae349f5Scvs2svn CcpInitRestartCounter(struct fsm *fp)
1941ae349f5Scvs2svn {
1957308ec68SBrian Somers   /* Set fsm timer load */
196cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
197cd9647a1SBrian Somers 
198cd9647a1SBrian Somers   fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS;
1991ae349f5Scvs2svn   fp->restart = 5;
2001ae349f5Scvs2svn }
2011ae349f5Scvs2svn 
2021ae349f5Scvs2svn static void
2031ae349f5Scvs2svn CcpSendConfigReq(struct fsm *fp)
2041ae349f5Scvs2svn {
2057308ec68SBrian Somers   /* Send config REQ please */
206aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
20703036ec7SBrian Somers   struct ccp_opt **o;
20830c2f2ffSBrian Somers   u_char *cp, buff[100];
20903036ec7SBrian Somers   int f, alloc;
2101ae349f5Scvs2svn 
21130c2f2ffSBrian Somers   cp = buff;
21203036ec7SBrian Somers   o = &ccp->out.opt;
21303036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
21483d1af55SBrian Somers   ccp->my_proto = -1;
21503036ec7SBrian Somers   ccp->out.algorithm = -1;
2161ae349f5Scvs2svn   for (f = 0; f < NALGORITHMS; f++)
21783d1af55SBrian Somers     if (Enabled(algorithm[f]->Conf) && !REJECTED(ccp, algorithm[f]->id)) {
21803036ec7SBrian Somers       if (alloc) {
21903036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
22003036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
22103036ec7SBrian Somers         (*o)->val.len = 2;
22203036ec7SBrian Somers         (*o)->next = NULL;
22303036ec7SBrian Somers         (*o)->algorithm = f;
22403036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
22503036ec7SBrian Somers       } else {
22603036ec7SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
22703036ec7SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
22803036ec7SBrian Somers             break;
22903036ec7SBrian Somers         if (*o == NULL) {
23003036ec7SBrian Somers           LogPrintf(LogERROR, "CCP REQ buffer lost !\n");
23103036ec7SBrian Somers           break;
23203036ec7SBrian Somers         }
23303036ec7SBrian Somers       }
2341ae349f5Scvs2svn 
23503036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
23630c2f2ffSBrian Somers         LogPrintf(LogERROR, "CCP REQ buffer overrun !\n");
23730c2f2ffSBrian Somers         break;
23830c2f2ffSBrian Somers       }
2392267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2402267893fSBrian Somers       cp += (*o)->val.len;
24103036ec7SBrian Somers 
24203036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
24303036ec7SBrian Somers       ccp->out.algorithm = f;
24403036ec7SBrian Somers 
24503036ec7SBrian Somers       if (alloc)
24603036ec7SBrian Somers         o = &(*o)->next;
2471ae349f5Scvs2svn     }
2482267893fSBrian Somers 
2492267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff);
2501ae349f5Scvs2svn }
2511ae349f5Scvs2svn 
2521ae349f5Scvs2svn void
2531ae349f5Scvs2svn CcpSendResetReq(struct fsm *fp)
2541ae349f5Scvs2svn {
2557308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
256aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2572267893fSBrian Somers 
25883d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
25983d1af55SBrian Somers   ccp->last_reset = -1;
2601ae349f5Scvs2svn   FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
2611ae349f5Scvs2svn }
2621ae349f5Scvs2svn 
2631ae349f5Scvs2svn static void
2642267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
2651ae349f5Scvs2svn {
2667308ec68SBrian Somers   /* Term REQ just sent by FSM */
2671ae349f5Scvs2svn }
2681ae349f5Scvs2svn 
2691ae349f5Scvs2svn static void
2702267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
2711ae349f5Scvs2svn {
2727308ec68SBrian Somers   /* Send Term ACK please */
2732267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
2741ae349f5Scvs2svn }
2751ae349f5Scvs2svn 
276503a7782SBrian Somers static void
2771ae349f5Scvs2svn CcpRecvResetReq(struct fsm *fp)
2781ae349f5Scvs2svn {
2797308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
280aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
28103036ec7SBrian Somers   if (ccp->out.state != NULL)
28203036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
2831ae349f5Scvs2svn }
2841ae349f5Scvs2svn 
2851ae349f5Scvs2svn static void
2861ae349f5Scvs2svn CcpLayerStart(struct fsm *fp)
2871ae349f5Scvs2svn {
2887308ec68SBrian Somers   /* We're about to start up ! */
2891ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerStart.\n");
2901ae349f5Scvs2svn }
2911ae349f5Scvs2svn 
2921ae349f5Scvs2svn static void
2931ae349f5Scvs2svn CcpLayerFinish(struct fsm *fp)
2941ae349f5Scvs2svn {
2957308ec68SBrian Somers   /* We're now down */
296aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2971ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerFinish.\n");
29803036ec7SBrian Somers   if (ccp->in.state != NULL) {
29903036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
30003036ec7SBrian Somers     ccp->in.state = NULL;
3017308ec68SBrian Somers   }
30203036ec7SBrian Somers   if (ccp->out.state != NULL) {
30303036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
30403036ec7SBrian Somers     ccp->out.state = NULL;
3057308ec68SBrian Somers   }
3061ae349f5Scvs2svn }
3071ae349f5Scvs2svn 
3081ae349f5Scvs2svn static void
3091ae349f5Scvs2svn CcpLayerDown(struct fsm *fp)
3101ae349f5Scvs2svn {
3117308ec68SBrian Somers   /* About to come down */
3121ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerDown.\n");
3131ae349f5Scvs2svn }
3141ae349f5Scvs2svn 
3151ae349f5Scvs2svn /*
3161ae349f5Scvs2svn  *  Called when CCP has reached the OPEN state
3171ae349f5Scvs2svn  */
3181ae349f5Scvs2svn static void
3191ae349f5Scvs2svn CcpLayerUp(struct fsm *fp)
3201ae349f5Scvs2svn {
3217308ec68SBrian Somers   /* We're now up */
322aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
323455aabc3SBrian Somers   LogPrintf(LogCCP, "CcpLayerUp.\n");
32403036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
32503036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
32603036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
32703036ec7SBrian Somers     if (ccp->in.state == NULL) {
328247ab36dSBrian Somers       LogPrintf(LogERROR, "%s (in) initialisation failure\n",
32983d1af55SBrian Somers                 protoname(ccp->his_proto));
33083d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
331247ab36dSBrian Somers       FsmClose(fp);
332247ab36dSBrian Somers     }
33303036ec7SBrian Somers   }
33403036ec7SBrian Somers 
33503036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
33603036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
33703036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
33803036ec7SBrian Somers                        (&ccp->out.opt->val);
33903036ec7SBrian Somers     if (ccp->out.state == NULL) {
340247ab36dSBrian Somers       LogPrintf(LogERROR, "%s (out) initialisation failure\n",
34183d1af55SBrian Somers                 protoname(ccp->my_proto));
34283d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
343247ab36dSBrian Somers       FsmClose(fp);
344247ab36dSBrian Somers     }
34503036ec7SBrian Somers   }
34603036ec7SBrian Somers 
3471ae349f5Scvs2svn   LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n",
34883d1af55SBrian Somers             protoname(ccp->my_proto), ccp->my_proto,
34983d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
3501ae349f5Scvs2svn }
3511ae349f5Scvs2svn 
3521ae349f5Scvs2svn static void
35330c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
35430c2f2ffSBrian Somers                 struct fsm_decode *dec)
3551ae349f5Scvs2svn {
3567308ec68SBrian Somers   /* Deal with incoming data */
357aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3581ae349f5Scvs2svn   int type, length;
3591ae349f5Scvs2svn   int f;
36003036ec7SBrian Somers   const char *end;
3611ae349f5Scvs2svn 
3621ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
3631ae349f5Scvs2svn     type = *cp;
3641ae349f5Scvs2svn     length = cp[1];
36503036ec7SBrian Somers 
36603036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
36703036ec7SBrian Somers       length = sizeof(struct lcp_opt);
36803036ec7SBrian Somers       LogPrintf(LogCCP, "Warning: Truncating length to %d\n", length);
36903036ec7SBrian Somers     }
3701ae349f5Scvs2svn 
3711ae349f5Scvs2svn     for (f = NALGORITHMS-1; f > -1; f--)
3721ae349f5Scvs2svn       if (algorithm[f]->id == type)
3731ae349f5Scvs2svn         break;
3741ae349f5Scvs2svn 
37503036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
37603036ec7SBrian Somers     if (end == NULL)
37703036ec7SBrian Somers       end = "";
37803036ec7SBrian Somers 
37903036ec7SBrian Somers     if (type < NCFTYPES)
38003036ec7SBrian Somers       LogPrintf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
38103036ec7SBrian Somers     else
38203036ec7SBrian Somers       LogPrintf(LogCCP, " ???[%d] %s\n", length, end);
38303036ec7SBrian Somers 
3841ae349f5Scvs2svn     if (f == -1) {
3851ae349f5Scvs2svn       /* Don't understand that :-( */
3861ae349f5Scvs2svn       if (mode_type == MODE_REQ) {
38783d1af55SBrian Somers         ccp->my_reject |= (1 << type);
38830c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
38930c2f2ffSBrian Somers         dec->rejend += length;
3901ae349f5Scvs2svn       }
3911ae349f5Scvs2svn     } else {
39203036ec7SBrian Somers       struct ccp_opt *o;
3931ae349f5Scvs2svn 
3941ae349f5Scvs2svn       switch (mode_type) {
3951ae349f5Scvs2svn       case MODE_REQ:
39603036ec7SBrian Somers 	if (Acceptable(algorithm[f]->Conf) && ccp->in.algorithm == -1) {
39703036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
39803036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
3991ae349f5Scvs2svn           case MODE_REJ:
40003036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
40103036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4021ae349f5Scvs2svn             break;
4031ae349f5Scvs2svn           case MODE_NAK:
40403036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
40503036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4061ae349f5Scvs2svn             break;
4071ae349f5Scvs2svn           case MODE_ACK:
40830c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
40930c2f2ffSBrian Somers 	    dec->ackend += length;
41083d1af55SBrian Somers 	    ccp->his_proto = type;
41103036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4121ae349f5Scvs2svn             break;
4131ae349f5Scvs2svn           }
4141ae349f5Scvs2svn 	} else {
41530c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
41630c2f2ffSBrian Somers 	  dec->rejend += length;
4171ae349f5Scvs2svn 	}
4181ae349f5Scvs2svn 	break;
4191ae349f5Scvs2svn       case MODE_NAK:
42003036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
42103036ec7SBrian Somers           if (o->val.id == cp[0])
42203036ec7SBrian Somers             break;
42303036ec7SBrian Somers         if (o == NULL)
42403036ec7SBrian Somers           LogPrintf(LogCCP, "Warning: Ignoring peer NAK of unsent option\n");
42503036ec7SBrian Somers         else {
42603036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
42703036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
42883d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4291ae349f5Scvs2svn           else {
43083d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
43183d1af55SBrian Somers 	    ccp->my_proto = -1;
4321ae349f5Scvs2svn           }
43303036ec7SBrian Somers         }
4341ae349f5Scvs2svn         break;
4351ae349f5Scvs2svn       case MODE_REJ:
43683d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
43783d1af55SBrian Somers 	ccp->my_proto = -1;
4381ae349f5Scvs2svn 	break;
4391ae349f5Scvs2svn       }
4401ae349f5Scvs2svn     }
4411ae349f5Scvs2svn 
44203036ec7SBrian Somers     plen -= cp[1];
44303036ec7SBrian Somers     cp += cp[1];
4441ae349f5Scvs2svn   }
4451ae349f5Scvs2svn 
44630c2f2ffSBrian Somers   if (mode_type != MODE_NOP && dec->rejend != dec->rej) {
44703036ec7SBrian Somers     /* rejects are preferred */
44803036ec7SBrian Somers     dec->ackend = dec->ack;
44903036ec7SBrian Somers     dec->nakend = dec->nak;
45003036ec7SBrian Somers     if (ccp->in.state == NULL) {
45183d1af55SBrian Somers       ccp->his_proto = -1;
45203036ec7SBrian Somers       ccp->in.algorithm = -1;
45303036ec7SBrian Somers     }
45403036ec7SBrian Somers   } else if (mode_type != MODE_NOP && dec->nakend != dec->nak) {
45503036ec7SBrian Somers     /* then NAKs */
45603036ec7SBrian Somers     dec->ackend = dec->ack;
45703036ec7SBrian Somers     if (ccp->in.state == NULL) {
45803036ec7SBrian Somers       ccp->his_proto = -1;
45903036ec7SBrian Somers       ccp->in.algorithm = -1;
460247ab36dSBrian Somers     }
4611ae349f5Scvs2svn   }
4621ae349f5Scvs2svn }
4631ae349f5Scvs2svn 
4641ae349f5Scvs2svn void
465f4768038SBrian Somers CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
4661ae349f5Scvs2svn {
4677308ec68SBrian Somers   /* Got PROTO_CCP from link */
468455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
469f4768038SBrian Somers     FsmInput(&ccp->fsm, bp);
470455aabc3SBrian Somers   else if (bundle_Phase(bundle) < PHASE_NETWORK) {
471455aabc3SBrian Somers     LogPrintf(LogCCP, "Error: Unexpected CCP in phase %s (ignored)\n",
472455aabc3SBrian Somers               bundle_PhaseName(bundle));
4731ae349f5Scvs2svn     pfree(bp);
4741ae349f5Scvs2svn   }
4751ae349f5Scvs2svn }
4761ae349f5Scvs2svn 
477503a7782SBrian Somers static void
478503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
4791ae349f5Scvs2svn {
4807308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
481f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
482f4768038SBrian Somers 
483f4768038SBrian Somers   if (ccp->reset_sent != -1) {
484f4768038SBrian Somers     if (id != ccp->reset_sent) {
4851ae349f5Scvs2svn       LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n",
486f4768038SBrian Somers                 id, ccp->reset_sent);
4871ae349f5Scvs2svn       return;
4881ae349f5Scvs2svn     }
4891ae349f5Scvs2svn     /* Whaddaya know - a correct reset ack */
490f4768038SBrian Somers   } else if (id == ccp->last_reset)
4911ae349f5Scvs2svn     LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n");
4921ae349f5Scvs2svn   else {
4931ae349f5Scvs2svn     LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id);
4941ae349f5Scvs2svn     return;
4951ae349f5Scvs2svn   }
4961ae349f5Scvs2svn 
497f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
498f4768038SBrian Somers   ccp->reset_sent = -1;
49903036ec7SBrian Somers   if (ccp->in.state != NULL)
50003036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5011ae349f5Scvs2svn }
5021ae349f5Scvs2svn 
5031ae349f5Scvs2svn int
5043b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
505503a7782SBrian Somers              struct mbuf *m)
5061ae349f5Scvs2svn {
507503a7782SBrian Somers   /* Compress outgoing Network Layer data */
50803036ec7SBrian Somers   if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED &&
50903036ec7SBrian Somers       ccp->out.state != NULL)
51003036ec7SBrian Somers     return (*algorithm[ccp->out.algorithm]->o.Write)
51103036ec7SBrian Somers              (ccp->out.state, ccp, l, pri, proto, m);
5121ae349f5Scvs2svn   return 0;
5131ae349f5Scvs2svn }
5141ae349f5Scvs2svn 
5151ae349f5Scvs2svn struct mbuf *
516503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
5171ae349f5Scvs2svn {
518ee6c193fSBrian Somers   /*
519ee6c193fSBrian Somers    * If proto isn't PROTO_COMPD, we still want to pass it to the
520ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
521ee6c193fSBrian Somers    */
522503a7782SBrian Somers   if (ccp->fsm.state == ST_OPENED)
523ee6c193fSBrian Somers     if (*proto == PROTO_COMPD) {
5247308ec68SBrian Somers       /* Decompress incoming data */
5252267893fSBrian Somers       if (ccp->reset_sent != -1)
5261ae349f5Scvs2svn         /* Send another REQ and put the packet in the bit bucket */
527503a7782SBrian Somers         FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
5282267893fSBrian Somers       else if (ccp->in.state != NULL)
52903036ec7SBrian Somers         return (*algorithm[ccp->in.algorithm]->i.Read)
53003036ec7SBrian Somers                  (ccp->in.state, ccp, proto, bp);
531ee6c193fSBrian Somers       pfree(bp);
532ee6c193fSBrian Somers       bp = NULL;
53303036ec7SBrian Somers     } else if ((*proto & 0xfff1) == 0x21 && ccp->in.state != NULL)
534ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
53503036ec7SBrian Somers       (*algorithm[ccp->in.algorithm]->i.DictSetup)
53603036ec7SBrian Somers         (ccp->in.state, ccp, *proto, bp);
5371ae349f5Scvs2svn 
538ee6c193fSBrian Somers   return bp;
5391ae349f5Scvs2svn }
540