xref: /freebsd/usr.sbin/ppp/ccp.c (revision 897f9429f97166298fd5ebc87d6f6b4688315aee)
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  *
20897f9429SBrian Somers  * $Id: ccp.c,v 1.34 1998/06/15 19:06:02 brian Exp $
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
23af57ed9fSAtsushi Murai  *		o Support other compression protocols
24af57ed9fSAtsushi Murai  */
252764b86aSBrian Somers #include <sys/types.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>
3385b542cfSBrian Somers #include <termios.h>
3475240ed1SBrian Somers 
35c9e11a11SBrian Somers #include "defs.h"
36b6e82f33SBrian Somers #include "command.h"
3775240ed1SBrian Somers #include "mbuf.h"
3875240ed1SBrian Somers #include "log.h"
3975240ed1SBrian Somers #include "timer.h"
40af57ed9fSAtsushi Murai #include "fsm.h"
41af57ed9fSAtsushi Murai #include "lcpproto.h"
42af57ed9fSAtsushi Murai #include "lcp.h"
43af57ed9fSAtsushi Murai #include "ccp.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"
495828db6dSBrian Somers #include "ipcp.h"
505ca5389aSBrian Somers #include "filter.h"
5185b542cfSBrian Somers #include "descriptor.h"
5285b542cfSBrian Somers #include "prompt.h"
53879ed6faSBrian Somers #include "lqr.h"
54503a7782SBrian Somers #include "hdlc.h"
55503a7782SBrian Somers #include "link.h"
563b0f8d2eSBrian Somers #include "mp.h"
57ed32233cSBrian Somers #include "async.h"
58ed32233cSBrian Somers #include "physical.h"
593b0f8d2eSBrian Somers #include "bundle.h"
60af57ed9fSAtsushi Murai 
61927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
622267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
632267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
6430c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
6530c2f2ffSBrian Somers                             struct fsm_decode *);
66927145beSBrian Somers static void CcpLayerStart(struct fsm *);
67927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
686f384573SBrian Somers static int CcpLayerUp(struct fsm *);
69927145beSBrian Somers static void CcpLayerDown(struct fsm *);
70927145beSBrian Somers static void CcpInitRestartCounter(struct fsm *);
71503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
72503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
73af57ed9fSAtsushi Murai 
7483d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
75af57ed9fSAtsushi Murai   CcpLayerUp,
76af57ed9fSAtsushi Murai   CcpLayerDown,
77af57ed9fSAtsushi Murai   CcpLayerStart,
78af57ed9fSAtsushi Murai   CcpLayerFinish,
79af57ed9fSAtsushi Murai   CcpInitRestartCounter,
80af57ed9fSAtsushi Murai   CcpSendConfigReq,
812267893fSBrian Somers   CcpSentTerminateReq,
82af57ed9fSAtsushi Murai   CcpSendTerminateAck,
83af57ed9fSAtsushi Murai   CcpDecodeConfig,
84503a7782SBrian Somers   CcpRecvResetReq,
85503a7782SBrian Somers   CcpRecvResetAck
86af57ed9fSAtsushi Murai };
87af57ed9fSAtsushi Murai 
886f384573SBrian Somers static const char *ccp_TimerNames[] =
896f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
906f384573SBrian Somers 
91e53374eaSPoul-Henning Kamp static char const *cftypes[] = {
929e836af5SBrian Somers   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
939e836af5SBrian Somers   "OUI",		/* 0: OUI */
949e836af5SBrian Somers   "PRED1",		/* 1: Predictor type 1 */
959e836af5SBrian Somers   "PRED2",		/* 2: Predictor type 2 */
969e836af5SBrian Somers   "PUDDLE",		/* 3: Puddle Jumber */
979e836af5SBrian Somers   "???", "???", "???", "???", "???", "???",
989e836af5SBrian Somers   "???", "???", "???", "???", "???", "???",
999e836af5SBrian Somers   "HWPPC",		/* 16: Hewlett-Packard PPC */
1004bc84b8cSBrian Somers   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
1018f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
1024bc84b8cSBrian Somers   "GAND",		/* 19: Gandalf FZA (rfc1993) */
103b6e82f33SBrian Somers   "V42BIS",		/* 20: ARG->DATA.42bis compression */
1040053cc58SBrian Somers   "BSD",		/* 21: BSD LZW Compress */
1050053cc58SBrian Somers   "???",
1064bc84b8cSBrian Somers   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1074bc84b8cSBrian Somers   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1081342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1094bc84b8cSBrian Somers   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1104bc84b8cSBrian Somers   "DEFLATE",		/* 26: Deflate (rfc1979) */
111af57ed9fSAtsushi Murai };
112af57ed9fSAtsushi Murai 
11370ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1149e836af5SBrian Somers 
1150053cc58SBrian Somers static const char *
1160053cc58SBrian Somers protoname(int proto)
1170053cc58SBrian Somers {
1180053cc58SBrian Somers   if (proto < 0 || proto > NCFTYPES)
1190053cc58SBrian Somers     return "none";
1200053cc58SBrian Somers   return cftypes[proto];
1210053cc58SBrian Somers }
1220053cc58SBrian Somers 
1234bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
1240053cc58SBrian Somers static const struct ccp_algorithm *algorithm[] = {
1254bc84b8cSBrian Somers   &DeflateAlgorithm,
1260053cc58SBrian Somers   &Pred1Algorithm,
1274bc84b8cSBrian Somers   &PppdDeflateAlgorithm
1280053cc58SBrian Somers };
1290053cc58SBrian Somers 
13070ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1310053cc58SBrian Somers 
132274e766cSBrian Somers int
133503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
134af57ed9fSAtsushi Murai {
135dd0645c5SBrian Somers   struct link *l;
136dd0645c5SBrian Somers   struct ccp *ccp;
137dd0645c5SBrian Somers 
138dd0645c5SBrian Somers   if (!(l = command_ChooseLink(arg)))
139dd0645c5SBrian Somers     return -1;
140dd0645c5SBrian Somers   ccp = &l->ccp;
141503a7782SBrian Somers 
142b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1431e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
144b6217683SBrian Somers   prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
145503a7782SBrian Somers                 protoname(ccp->my_proto), protoname(ccp->his_proto));
146b6217683SBrian Somers   prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
147503a7782SBrian Somers                 ccp->uncompout, ccp->compout,
148503a7782SBrian Somers                 ccp->compin, ccp->uncompin);
149cd9647a1SBrian Somers 
150b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
1511342caedSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry);
152b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
153b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
154b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1551342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1561342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1571342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1581342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1591342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1601342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
161274e766cSBrian Somers   return 0;
162af57ed9fSAtsushi Murai }
163af57ed9fSAtsushi Murai 
1641ae349f5Scvs2svn void
1656f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
166af57ed9fSAtsushi Murai {
1676f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
1686f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
1696f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
1706f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
171ea661041SBrian Somers }
172ea661041SBrian Somers 
173ea661041SBrian Somers void
1746d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1756d666775SBrian Somers          const struct fsm_parent *parent)
176ea661041SBrian Somers {
1777308ec68SBrian Somers   /* Initialise ourselves */
1783b0f8d2eSBrian Somers 
1793b0f8d2eSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
1806f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
181cd9647a1SBrian Somers 
18203036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
18303036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
184cd9647a1SBrian Somers   ccp->cfg.fsmretry = DEF_FSMRETRY;
1851342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
1861342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
1871342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
188cd9647a1SBrian Somers 
189503a7782SBrian Somers   ccp_Setup(ccp);
190503a7782SBrian Somers }
191503a7782SBrian Somers 
192503a7782SBrian Somers void
193503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
194503a7782SBrian Somers {
195503a7782SBrian Somers   /* Set ourselves up for a startup */
196503a7782SBrian Somers   ccp->fsm.open_mode = 0;
1975454ccd9SBrian Somers   ccp->fsm.maxconfig = 10;
198503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
199503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
20003036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
20103036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
20203036ec7SBrian Somers   ccp->in.opt.id = -1;
20303036ec7SBrian Somers   ccp->out.opt = NULL;
204503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
205503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
206503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
207af57ed9fSAtsushi Murai }
208af57ed9fSAtsushi Murai 
209af57ed9fSAtsushi Murai static void
210944f7098SBrian Somers CcpInitRestartCounter(struct fsm *fp)
211af57ed9fSAtsushi Murai {
2127308ec68SBrian Somers   /* Set fsm timer load */
213cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
214cd9647a1SBrian Somers 
215cd9647a1SBrian Somers   fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS;
216af57ed9fSAtsushi Murai   fp->restart = 5;
217af57ed9fSAtsushi Murai }
218af57ed9fSAtsushi Murai 
219af57ed9fSAtsushi Murai static void
220944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
221af57ed9fSAtsushi Murai {
2227308ec68SBrian Somers   /* Send config REQ please */
223aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
22403036ec7SBrian Somers   struct ccp_opt **o;
22530c2f2ffSBrian Somers   u_char *cp, buff[100];
22603036ec7SBrian Somers   int f, alloc;
227af57ed9fSAtsushi Murai 
22830c2f2ffSBrian Somers   cp = buff;
22903036ec7SBrian Somers   o = &ccp->out.opt;
23003036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
23183d1af55SBrian Somers   ccp->my_proto = -1;
23203036ec7SBrian Somers   ccp->out.algorithm = -1;
2330053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
2341342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2351342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
2360053cc58SBrian Somers 
237ba081e43SBrian Somers       if (!alloc)
238ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
239ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
240ba081e43SBrian Somers             break;
241ba081e43SBrian Somers 
242ba081e43SBrian Somers       if (alloc || *o == NULL) {
24303036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
24403036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
24503036ec7SBrian Somers         (*o)->val.len = 2;
24603036ec7SBrian Somers         (*o)->next = NULL;
24703036ec7SBrian Somers         (*o)->algorithm = f;
24803036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
249af57ed9fSAtsushi Murai       }
2501ae349f5Scvs2svn 
25103036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
252dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
25330c2f2ffSBrian Somers         break;
25430c2f2ffSBrian Somers       }
2552267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2562267893fSBrian Somers       cp += (*o)->val.len;
25703036ec7SBrian Somers 
25803036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
25903036ec7SBrian Somers       ccp->out.algorithm = f;
26003036ec7SBrian Somers 
26103036ec7SBrian Somers       if (alloc)
26203036ec7SBrian Somers         o = &(*o)->next;
2631ae349f5Scvs2svn     }
2642267893fSBrian Somers 
265dd7e2610SBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff);
266af57ed9fSAtsushi Murai }
267af57ed9fSAtsushi Murai 
268af57ed9fSAtsushi Murai void
269dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
270af57ed9fSAtsushi Murai {
2717308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
272aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2732267893fSBrian Somers 
27483d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
27583d1af55SBrian Somers   ccp->last_reset = -1;
276dd7e2610SBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
277af57ed9fSAtsushi Murai }
278af57ed9fSAtsushi Murai 
279af57ed9fSAtsushi Murai static void
2802267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
281af57ed9fSAtsushi Murai {
2827308ec68SBrian Somers   /* Term REQ just sent by FSM */
283af57ed9fSAtsushi Murai }
284af57ed9fSAtsushi Murai 
285af57ed9fSAtsushi Murai static void
2862267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
287af57ed9fSAtsushi Murai {
2887308ec68SBrian Somers   /* Send Term ACK please */
289dd7e2610SBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
290af57ed9fSAtsushi Murai }
291af57ed9fSAtsushi Murai 
292503a7782SBrian Somers static void
293944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
294af57ed9fSAtsushi Murai {
2957308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
296aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
29703036ec7SBrian Somers   if (ccp->out.state != NULL)
29803036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
299af57ed9fSAtsushi Murai }
300af57ed9fSAtsushi Murai 
301af57ed9fSAtsushi Murai static void
302944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
303af57ed9fSAtsushi Murai {
3047308ec68SBrian Somers   /* We're about to start up ! */
305dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: CcpLayerStart.\n", fp->link->name);
306af57ed9fSAtsushi Murai }
307af57ed9fSAtsushi Murai 
308af57ed9fSAtsushi Murai static void
309897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
310af57ed9fSAtsushi Murai {
311897f9429SBrian Somers   /* About to come down */
312aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
313ba081e43SBrian Somers   struct ccp_opt *next;
314ba081e43SBrian Somers 
315897f9429SBrian Somers   log_Printf(LogCCP, "%s: CcpLayerDown.\n", fp->link->name);
31603036ec7SBrian Somers   if (ccp->in.state != NULL) {
31703036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
31803036ec7SBrian Somers     ccp->in.state = NULL;
3198d9b9867SBrian Somers     ccp->in.algorithm = -1;
3207308ec68SBrian Somers   }
32103036ec7SBrian Somers   if (ccp->out.state != NULL) {
32203036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
32303036ec7SBrian Somers     ccp->out.state = NULL;
3248d9b9867SBrian Somers     ccp->out.algorithm = -1;
3257308ec68SBrian Somers   }
3268d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
327ba081e43SBrian Somers 
328ba081e43SBrian Somers   while (ccp->out.opt) {
329ba081e43SBrian Somers     next = ccp->out.opt->next;
330ba081e43SBrian Somers     free(ccp->out.opt);
331ba081e43SBrian Somers     ccp->out.opt = next;
332ba081e43SBrian Somers   }
333897f9429SBrian Somers   ccp_Setup(ccp);
334af57ed9fSAtsushi Murai }
335af57ed9fSAtsushi Murai 
336af57ed9fSAtsushi Murai static void
337897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
338af57ed9fSAtsushi Murai {
339897f9429SBrian Somers   /* We're now down */
340897f9429SBrian Somers   log_Printf(LogCCP, "%s: CcpLayerFinish.\n", fp->link->name);
341af57ed9fSAtsushi Murai }
342af57ed9fSAtsushi Murai 
343af57ed9fSAtsushi Murai /*
3440053cc58SBrian Somers  *  Called when CCP has reached the OPEN state
345af57ed9fSAtsushi Murai  */
3466f384573SBrian Somers static int
347944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
348af57ed9fSAtsushi Murai {
3497308ec68SBrian Somers   /* We're now up */
350aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
351dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: CcpLayerUp.\n", fp->link->name);
35203036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
35303036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
35403036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
35503036ec7SBrian Somers     if (ccp->in.state == NULL) {
356dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
357d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
35883d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
359dd7e2610SBrian Somers       fsm_Close(fp);
36079d1bdaeSBrian Somers     }
361af57ed9fSAtsushi Murai   }
362af57ed9fSAtsushi Murai 
36303036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
36403036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
36503036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
36603036ec7SBrian Somers                        (&ccp->out.opt->val);
36703036ec7SBrian Somers     if (ccp->out.state == NULL) {
368dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
369d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
37083d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
371dd7e2610SBrian Somers       fsm_Close(fp);
372247ab36dSBrian Somers     }
373af57ed9fSAtsushi Murai   }
374af57ed9fSAtsushi Murai 
375dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
376d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
37783d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
3786f384573SBrian Somers   return 1;
379af57ed9fSAtsushi Murai }
380af57ed9fSAtsushi Murai 
381af57ed9fSAtsushi Murai static void
38230c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
38330c2f2ffSBrian Somers                 struct fsm_decode *dec)
384af57ed9fSAtsushi Murai {
3857308ec68SBrian Somers   /* Deal with incoming data */
386aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
38753c9f6c0SAtsushi Murai   int type, length;
3880053cc58SBrian Somers   int f;
38903036ec7SBrian Somers   const char *end;
390af57ed9fSAtsushi Murai 
391af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
392af57ed9fSAtsushi Murai     type = *cp;
393af57ed9fSAtsushi Murai     length = cp[1];
39403036ec7SBrian Somers 
395d47dceb8SBrian Somers     if (length == 0) {
396dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
397d47dceb8SBrian Somers       break;
398d47dceb8SBrian Somers     }
399d47dceb8SBrian Somers 
40003036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
40103036ec7SBrian Somers       length = sizeof(struct lcp_opt);
402dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
403d47dceb8SBrian Somers                 fp->link->name, length);
40403036ec7SBrian Somers     }
405af57ed9fSAtsushi Murai 
4060053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
4070053cc58SBrian Somers       if (algorithm[f]->id == type)
4080053cc58SBrian Somers         break;
409af57ed9fSAtsushi Murai 
41003036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
41103036ec7SBrian Somers     if (end == NULL)
41203036ec7SBrian Somers       end = "";
41303036ec7SBrian Somers 
41403036ec7SBrian Somers     if (type < NCFTYPES)
415dd7e2610SBrian Somers       log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
41603036ec7SBrian Somers     else
417dd7e2610SBrian Somers       log_Printf(LogCCP, " ???[%d] %s\n", length, end);
41803036ec7SBrian Somers 
4190053cc58SBrian Somers     if (f == -1) {
4200053cc58SBrian Somers       /* Don't understand that :-( */
4210053cc58SBrian Somers       if (mode_type == MODE_REQ) {
42283d1af55SBrian Somers         ccp->my_reject |= (1 << type);
42330c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
42430c2f2ffSBrian Somers         dec->rejend += length;
4250053cc58SBrian Somers       }
4260053cc58SBrian Somers     } else {
42703036ec7SBrian Somers       struct ccp_opt *o;
4280053cc58SBrian Somers 
4299780ef31SBrian Somers       switch (mode_type) {
430af57ed9fSAtsushi Murai       case MODE_REQ:
4311342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
4321342caedSBrian Somers             ccp->in.algorithm == -1) {
43303036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
43403036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4350053cc58SBrian Somers           case MODE_REJ:
43603036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
43703036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4380053cc58SBrian Somers             break;
4390053cc58SBrian Somers           case MODE_NAK:
44003036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
44103036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4420053cc58SBrian Somers             break;
4430053cc58SBrian Somers           case MODE_ACK:
44430c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
44530c2f2ffSBrian Somers 	    dec->ackend += length;
44683d1af55SBrian Somers 	    ccp->his_proto = type;
44703036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4480053cc58SBrian Somers             break;
4490053cc58SBrian Somers           }
450af57ed9fSAtsushi Murai 	} else {
45130c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
45230c2f2ffSBrian Somers 	  dec->rejend += length;
453af57ed9fSAtsushi Murai 	}
454af57ed9fSAtsushi Murai 	break;
455af57ed9fSAtsushi Murai       case MODE_NAK:
45603036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
45703036ec7SBrian Somers           if (o->val.id == cp[0])
45803036ec7SBrian Somers             break;
45903036ec7SBrian Somers         if (o == NULL)
460dd7e2610SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n",
461d47dceb8SBrian Somers                     fp->link->name);
4620053cc58SBrian Somers         else {
46303036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
46403036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
46583d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4661ae349f5Scvs2svn           else {
46783d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
46883d1af55SBrian Somers 	    ccp->my_proto = -1;
4691ae349f5Scvs2svn           }
4700053cc58SBrian Somers         }
4710053cc58SBrian Somers         break;
472af57ed9fSAtsushi Murai       case MODE_REJ:
47383d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
47483d1af55SBrian Somers 	ccp->my_proto = -1;
475af57ed9fSAtsushi Murai 	break;
476af57ed9fSAtsushi Murai       }
477af57ed9fSAtsushi Murai     }
4780053cc58SBrian Somers 
47903036ec7SBrian Somers     plen -= cp[1];
48003036ec7SBrian Somers     cp += cp[1];
481af57ed9fSAtsushi Murai   }
4820053cc58SBrian Somers 
483e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
4841342caedSBrian Somers     if (dec->rejend != dec->rej) {
48503036ec7SBrian Somers       /* rejects are preferred */
48603036ec7SBrian Somers       dec->ackend = dec->ack;
48703036ec7SBrian Somers       dec->nakend = dec->nak;
48803036ec7SBrian Somers       if (ccp->in.state == NULL) {
48983d1af55SBrian Somers         ccp->his_proto = -1;
49003036ec7SBrian Somers         ccp->in.algorithm = -1;
49103036ec7SBrian Somers       }
4921342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
49303036ec7SBrian Somers       /* then NAKs */
49403036ec7SBrian Somers       dec->ackend = dec->ack;
49503036ec7SBrian Somers       if (ccp->in.state == NULL) {
49603036ec7SBrian Somers         ccp->his_proto = -1;
49703036ec7SBrian Somers         ccp->in.algorithm = -1;
498247ab36dSBrian Somers       }
4991ae349f5Scvs2svn     }
5000053cc58SBrian Somers   }
501af57ed9fSAtsushi Murai }
502af57ed9fSAtsushi Murai 
503af57ed9fSAtsushi Murai void
504dd7e2610SBrian Somers ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
505af57ed9fSAtsushi Murai {
5067308ec68SBrian Somers   /* Got PROTO_CCP from link */
507455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
508dd7e2610SBrian Somers     fsm_Input(&ccp->fsm, bp);
509af57ed9fSAtsushi Murai   else {
510641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
511dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
512d47dceb8SBrian Somers                  ccp->fsm.link->name, bundle_PhaseName(bundle));
513dd7e2610SBrian Somers     mbuf_Free(bp);
514af57ed9fSAtsushi Murai   }
515af57ed9fSAtsushi Murai }
5160053cc58SBrian Somers 
517503a7782SBrian Somers static void
518503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5190053cc58SBrian Somers {
5207308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
521f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
522f4768038SBrian Somers 
523f4768038SBrian Somers   if (ccp->reset_sent != -1) {
524f4768038SBrian Somers     if (id != ccp->reset_sent) {
525dd7e2610SBrian Somers       log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)"
526d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
52798baf7c8SBrian Somers       return;
52898baf7c8SBrian Somers     }
52998baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
530f4768038SBrian Somers   } else if (id == ccp->last_reset)
531dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
532d47dceb8SBrian Somers               fp->link->name);
53398baf7c8SBrian Somers   else {
534dd7e2610SBrian Somers     log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n",
535d47dceb8SBrian Somers               fp->link->name, id);
53698baf7c8SBrian Somers     return;
53798baf7c8SBrian Somers   }
53898baf7c8SBrian Somers 
539f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
540f4768038SBrian Somers   ccp->reset_sent = -1;
54103036ec7SBrian Somers   if (ccp->in.state != NULL)
54203036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5430053cc58SBrian Somers }
5440053cc58SBrian Somers 
5450053cc58SBrian Somers int
5463b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
547503a7782SBrian Somers              struct mbuf *m)
5480053cc58SBrian Somers {
5490a1b5c9dSBrian Somers   /*
5500a1b5c9dSBrian Somers    * Compress outgoing data.  It's already deemed to be suitable Network
5510a1b5c9dSBrian Somers    * Layer data.
5520a1b5c9dSBrian Somers    */
5530a1b5c9dSBrian Somers   if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL)
55403036ec7SBrian Somers     return (*algorithm[ccp->out.algorithm]->o.Write)
55503036ec7SBrian Somers              (ccp->out.state, ccp, l, pri, proto, m);
5560053cc58SBrian Somers   return 0;
5570053cc58SBrian Somers }
5580053cc58SBrian Somers 
5590053cc58SBrian Somers struct mbuf *
560503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
5610053cc58SBrian Somers {
562ee6c193fSBrian Somers   /*
563ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
564ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
565ee6c193fSBrian Somers    */
566e43ebac1SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
567ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
5687308ec68SBrian Somers       /* Decompress incoming data */
5692267893fSBrian Somers       if (ccp->reset_sent != -1)
57098baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
571dd7e2610SBrian Somers         fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
5722267893fSBrian Somers       else if (ccp->in.state != NULL)
57303036ec7SBrian Somers         return (*algorithm[ccp->in.algorithm]->i.Read)
57403036ec7SBrian Somers                  (ccp->in.state, ccp, proto, bp);
575dd7e2610SBrian Somers       mbuf_Free(bp);
576ee6c193fSBrian Somers       bp = NULL;
5770a1b5c9dSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL)
578ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
57903036ec7SBrian Somers       (*algorithm[ccp->in.algorithm]->i.DictSetup)
58003036ec7SBrian Somers         (ccp->in.state, ccp, *proto, bp);
5810053cc58SBrian Somers   }
5820053cc58SBrian Somers 
583ee6c193fSBrian Somers   return bp;
5841ae349f5Scvs2svn }
585ed32233cSBrian Somers 
586ed32233cSBrian Somers u_short
587ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
5880053cc58SBrian Somers {
589ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
590ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
5910053cc58SBrian Somers }
5921df0a3b9SBrian Somers 
5931df0a3b9SBrian Somers void
5941df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
5951df0a3b9SBrian Somers {
5961df0a3b9SBrian Somers   int f;
5971df0a3b9SBrian Somers 
5981df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
5991df0a3b9SBrian Somers     if (ccp->cfg.neg[f])
6001df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
6011df0a3b9SBrian Somers 
6021df0a3b9SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED */
6031df0a3b9SBrian Somers }
604