xref: /freebsd/usr.sbin/ppp/ccp.c (revision 972a1bcf5db5ee4c5520a1d29d3c81e81bdec84f)
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  *
20972a1bcfSBrian Somers  * $Id: ccp.c,v 1.40 1998/08/26 18:07:56 brian Exp $
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
23af57ed9fSAtsushi Murai  *		o Support other compression protocols
24af57ed9fSAtsushi Murai  */
25972a1bcfSBrian Somers #include <sys/param.h>
2675240ed1SBrian Somers #include <netinet/in.h>
27eaa4df37SBrian Somers #include <netinet/in_systm.h>
28eaa4df37SBrian Somers #include <netinet/ip.h>
291fa665f5SBrian Somers #include <sys/un.h>
3075240ed1SBrian Somers 
3175240ed1SBrian Somers #include <stdio.h>
3203036ec7SBrian Somers #include <stdlib.h>
3337d818fbSBrian Somers #include <string.h>
3485b542cfSBrian Somers #include <termios.h>
3575240ed1SBrian Somers 
36c9e11a11SBrian Somers #include "defs.h"
37b6e82f33SBrian Somers #include "command.h"
3875240ed1SBrian Somers #include "mbuf.h"
3975240ed1SBrian Somers #include "log.h"
4075240ed1SBrian Somers #include "timer.h"
41af57ed9fSAtsushi Murai #include "fsm.h"
42af57ed9fSAtsushi Murai #include "lcpproto.h"
43af57ed9fSAtsushi Murai #include "lcp.h"
44af57ed9fSAtsushi Murai #include "ccp.h"
45ed6a16c1SPoul-Henning Kamp #include "pred.h"
460053cc58SBrian Somers #include "deflate.h"
475828db6dSBrian Somers #include "throughput.h"
485828db6dSBrian Somers #include "iplist.h"
49eaa4df37SBrian Somers #include "slcompress.h"
505a72b6edSBrian Somers #include "lqr.h"
515a72b6edSBrian Somers #include "hdlc.h"
525828db6dSBrian Somers #include "ipcp.h"
535ca5389aSBrian Somers #include "filter.h"
5485b542cfSBrian Somers #include "descriptor.h"
5585b542cfSBrian Somers #include "prompt.h"
56503a7782SBrian Somers #include "link.h"
573b0f8d2eSBrian Somers #include "mp.h"
58ed32233cSBrian Somers #include "async.h"
59ed32233cSBrian Somers #include "physical.h"
60972a1bcfSBrian Somers #ifndef NORADIUS
61972a1bcfSBrian Somers #include "radius.h"
62972a1bcfSBrian Somers #endif
633b0f8d2eSBrian Somers #include "bundle.h"
64af57ed9fSAtsushi Murai 
65927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
662267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
672267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
6830c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
6930c2f2ffSBrian Somers                             struct fsm_decode *);
70927145beSBrian Somers static void CcpLayerStart(struct fsm *);
71927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
726f384573SBrian Somers static int CcpLayerUp(struct fsm *);
73927145beSBrian Somers static void CcpLayerDown(struct fsm *);
74927145beSBrian Somers static void CcpInitRestartCounter(struct fsm *);
75503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
76503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
77af57ed9fSAtsushi Murai 
7883d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
79af57ed9fSAtsushi Murai   CcpLayerUp,
80af57ed9fSAtsushi Murai   CcpLayerDown,
81af57ed9fSAtsushi Murai   CcpLayerStart,
82af57ed9fSAtsushi Murai   CcpLayerFinish,
83af57ed9fSAtsushi Murai   CcpInitRestartCounter,
84af57ed9fSAtsushi Murai   CcpSendConfigReq,
852267893fSBrian Somers   CcpSentTerminateReq,
86af57ed9fSAtsushi Murai   CcpSendTerminateAck,
87af57ed9fSAtsushi Murai   CcpDecodeConfig,
88503a7782SBrian Somers   CcpRecvResetReq,
89503a7782SBrian Somers   CcpRecvResetAck
90af57ed9fSAtsushi Murai };
91af57ed9fSAtsushi Murai 
926f384573SBrian Somers static const char *ccp_TimerNames[] =
936f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
946f384573SBrian Somers 
95e53374eaSPoul-Henning Kamp static char const *cftypes[] = {
969e836af5SBrian Somers   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
979e836af5SBrian Somers   "OUI",		/* 0: OUI */
989e836af5SBrian Somers   "PRED1",		/* 1: Predictor type 1 */
999e836af5SBrian Somers   "PRED2",		/* 2: Predictor type 2 */
1009e836af5SBrian Somers   "PUDDLE",		/* 3: Puddle Jumber */
1019e836af5SBrian Somers   "???", "???", "???", "???", "???", "???",
1029e836af5SBrian Somers   "???", "???", "???", "???", "???", "???",
1039e836af5SBrian Somers   "HWPPC",		/* 16: Hewlett-Packard PPC */
1044bc84b8cSBrian Somers   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
1058f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
1064bc84b8cSBrian Somers   "GAND",		/* 19: Gandalf FZA (rfc1993) */
107b6e82f33SBrian Somers   "V42BIS",		/* 20: ARG->DATA.42bis compression */
1080053cc58SBrian Somers   "BSD",		/* 21: BSD LZW Compress */
1090053cc58SBrian Somers   "???",
1104bc84b8cSBrian Somers   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1114bc84b8cSBrian Somers   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1121342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1134bc84b8cSBrian Somers   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1144bc84b8cSBrian Somers   "DEFLATE",		/* 26: Deflate (rfc1979) */
115af57ed9fSAtsushi Murai };
116af57ed9fSAtsushi Murai 
11770ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1189e836af5SBrian Somers 
1190053cc58SBrian Somers static const char *
1200053cc58SBrian Somers protoname(int proto)
1210053cc58SBrian Somers {
1220053cc58SBrian Somers   if (proto < 0 || proto > NCFTYPES)
1230053cc58SBrian Somers     return "none";
1240053cc58SBrian Somers   return cftypes[proto];
1250053cc58SBrian Somers }
1260053cc58SBrian Somers 
1274bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
1280053cc58SBrian Somers static const struct ccp_algorithm *algorithm[] = {
1294bc84b8cSBrian Somers   &DeflateAlgorithm,
1300053cc58SBrian Somers   &Pred1Algorithm,
1314bc84b8cSBrian Somers   &PppdDeflateAlgorithm
1320053cc58SBrian Somers };
1330053cc58SBrian Somers 
13470ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1350053cc58SBrian Somers 
136274e766cSBrian Somers int
137503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
138af57ed9fSAtsushi Murai {
139dd0645c5SBrian Somers   struct link *l;
140dd0645c5SBrian Somers   struct ccp *ccp;
141dd0645c5SBrian Somers 
1423a2e4f62SBrian Somers   l = command_ChooseLink(arg);
143dd0645c5SBrian Somers   ccp = &l->ccp;
144503a7782SBrian Somers 
145b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1461e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
147b6217683SBrian Somers   prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
148503a7782SBrian Somers                 protoname(ccp->my_proto), protoname(ccp->his_proto));
149b6217683SBrian Somers   prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
150503a7782SBrian Somers                 ccp->uncompout, ccp->compout,
151503a7782SBrian Somers                 ccp->compin, ccp->uncompin);
152cd9647a1SBrian Somers 
153b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
1541342caedSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry);
155b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
156b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
157b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1581342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1591342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1601342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1611342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1621342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1631342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
164274e766cSBrian Somers   return 0;
165af57ed9fSAtsushi Murai }
166af57ed9fSAtsushi Murai 
1671ae349f5Scvs2svn void
1686f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
169af57ed9fSAtsushi Murai {
1706f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
1716f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
1726f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
1736f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
174ea661041SBrian Somers }
175ea661041SBrian Somers 
176ea661041SBrian Somers void
1776d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1786d666775SBrian Somers          const struct fsm_parent *parent)
179ea661041SBrian Somers {
1807308ec68SBrian Somers   /* Initialise ourselves */
1813b0f8d2eSBrian Somers 
1823b0f8d2eSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
1836f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
184cd9647a1SBrian Somers 
18503036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
18603036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
187cd9647a1SBrian Somers   ccp->cfg.fsmretry = DEF_FSMRETRY;
1881342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
1891342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
1901342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
191cd9647a1SBrian Somers 
192503a7782SBrian Somers   ccp_Setup(ccp);
193503a7782SBrian Somers }
194503a7782SBrian Somers 
195503a7782SBrian Somers void
196503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
197503a7782SBrian Somers {
198503a7782SBrian Somers   /* Set ourselves up for a startup */
199503a7782SBrian Somers   ccp->fsm.open_mode = 0;
2005454ccd9SBrian Somers   ccp->fsm.maxconfig = 10;
201503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
202503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
20303036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
20403036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
20503036ec7SBrian Somers   ccp->in.opt.id = -1;
20603036ec7SBrian Somers   ccp->out.opt = NULL;
207503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
208503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
209503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
210af57ed9fSAtsushi Murai }
211af57ed9fSAtsushi Murai 
212af57ed9fSAtsushi Murai static void
213944f7098SBrian Somers CcpInitRestartCounter(struct fsm *fp)
214af57ed9fSAtsushi Murai {
2157308ec68SBrian Somers   /* Set fsm timer load */
216cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
217cd9647a1SBrian Somers 
218cd9647a1SBrian Somers   fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS;
21992b09558SBrian Somers   fp->restart = DEF_REQs;
220af57ed9fSAtsushi Murai }
221af57ed9fSAtsushi Murai 
222af57ed9fSAtsushi Murai static void
223944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
224af57ed9fSAtsushi Murai {
2257308ec68SBrian Somers   /* Send config REQ please */
226aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
22703036ec7SBrian Somers   struct ccp_opt **o;
22830c2f2ffSBrian Somers   u_char *cp, buff[100];
22903036ec7SBrian Somers   int f, alloc;
230af57ed9fSAtsushi Murai 
23130c2f2ffSBrian Somers   cp = buff;
23203036ec7SBrian Somers   o = &ccp->out.opt;
23303036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
23483d1af55SBrian Somers   ccp->my_proto = -1;
23503036ec7SBrian Somers   ccp->out.algorithm = -1;
2360053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
2371342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2381342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
2390053cc58SBrian Somers 
240ba081e43SBrian Somers       if (!alloc)
241ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
242ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
243ba081e43SBrian Somers             break;
244ba081e43SBrian Somers 
245ba081e43SBrian Somers       if (alloc || *o == NULL) {
24603036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
24703036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
24803036ec7SBrian Somers         (*o)->val.len = 2;
24903036ec7SBrian Somers         (*o)->next = NULL;
25003036ec7SBrian Somers         (*o)->algorithm = f;
25103036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
252af57ed9fSAtsushi Murai       }
2531ae349f5Scvs2svn 
25403036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
255dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
25630c2f2ffSBrian Somers         break;
25730c2f2ffSBrian Somers       }
2582267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2592267893fSBrian Somers       cp += (*o)->val.len;
26003036ec7SBrian Somers 
26103036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
26203036ec7SBrian Somers       ccp->out.algorithm = f;
26303036ec7SBrian Somers 
26403036ec7SBrian Somers       if (alloc)
26503036ec7SBrian Somers         o = &(*o)->next;
2661ae349f5Scvs2svn     }
2672267893fSBrian Somers 
268dd7e2610SBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff);
269af57ed9fSAtsushi Murai }
270af57ed9fSAtsushi Murai 
271af57ed9fSAtsushi Murai void
272dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
273af57ed9fSAtsushi Murai {
2747308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
275aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2762267893fSBrian Somers 
27783d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
27883d1af55SBrian Somers   ccp->last_reset = -1;
279dd7e2610SBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
280af57ed9fSAtsushi Murai }
281af57ed9fSAtsushi Murai 
282af57ed9fSAtsushi Murai static void
2832267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
284af57ed9fSAtsushi Murai {
2857308ec68SBrian Somers   /* Term REQ just sent by FSM */
286af57ed9fSAtsushi Murai }
287af57ed9fSAtsushi Murai 
288af57ed9fSAtsushi Murai static void
2892267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
290af57ed9fSAtsushi Murai {
2917308ec68SBrian Somers   /* Send Term ACK please */
292dd7e2610SBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
293af57ed9fSAtsushi Murai }
294af57ed9fSAtsushi Murai 
295503a7782SBrian Somers static void
296944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
297af57ed9fSAtsushi Murai {
2987308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
299aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
30003036ec7SBrian Somers   if (ccp->out.state != NULL)
30103036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
302af57ed9fSAtsushi Murai }
303af57ed9fSAtsushi Murai 
304af57ed9fSAtsushi Murai static void
305944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
306af57ed9fSAtsushi Murai {
3077308ec68SBrian Somers   /* We're about to start up ! */
3083a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
309af57ed9fSAtsushi Murai }
310af57ed9fSAtsushi Murai 
311af57ed9fSAtsushi Murai static void
312897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
313af57ed9fSAtsushi Murai {
314897f9429SBrian Somers   /* About to come down */
315aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
316ba081e43SBrian Somers   struct ccp_opt *next;
317ba081e43SBrian Somers 
3183a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
31903036ec7SBrian Somers   if (ccp->in.state != NULL) {
32003036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
32103036ec7SBrian Somers     ccp->in.state = NULL;
3228d9b9867SBrian Somers     ccp->in.algorithm = -1;
3237308ec68SBrian Somers   }
32403036ec7SBrian Somers   if (ccp->out.state != NULL) {
32503036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
32603036ec7SBrian Somers     ccp->out.state = NULL;
3278d9b9867SBrian Somers     ccp->out.algorithm = -1;
3287308ec68SBrian Somers   }
3298d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
330ba081e43SBrian Somers 
331ba081e43SBrian Somers   while (ccp->out.opt) {
332ba081e43SBrian Somers     next = ccp->out.opt->next;
333ba081e43SBrian Somers     free(ccp->out.opt);
334ba081e43SBrian Somers     ccp->out.opt = next;
335ba081e43SBrian Somers   }
336897f9429SBrian Somers   ccp_Setup(ccp);
337af57ed9fSAtsushi Murai }
338af57ed9fSAtsushi Murai 
339af57ed9fSAtsushi Murai static void
340897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
341af57ed9fSAtsushi Murai {
342897f9429SBrian Somers   /* We're now down */
3433a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
344af57ed9fSAtsushi Murai }
345af57ed9fSAtsushi Murai 
346af57ed9fSAtsushi Murai /*
3470053cc58SBrian Somers  *  Called when CCP has reached the OPEN state
348af57ed9fSAtsushi Murai  */
3496f384573SBrian Somers static int
350944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
351af57ed9fSAtsushi Murai {
3527308ec68SBrian Somers   /* We're now up */
353aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3543a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
35503036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
35603036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
35703036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
35803036ec7SBrian Somers     if (ccp->in.state == NULL) {
359dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
360d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
36183d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
362dd7e2610SBrian Somers       fsm_Close(fp);
36379d1bdaeSBrian Somers     }
364af57ed9fSAtsushi Murai   }
365af57ed9fSAtsushi Murai 
36603036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
36703036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
36803036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
36903036ec7SBrian Somers                        (&ccp->out.opt->val);
37003036ec7SBrian Somers     if (ccp->out.state == NULL) {
371dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
372d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
37383d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
374dd7e2610SBrian Somers       fsm_Close(fp);
375247ab36dSBrian Somers     }
376af57ed9fSAtsushi Murai   }
377af57ed9fSAtsushi Murai 
378dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
379d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
38083d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
3816f384573SBrian Somers   return 1;
382af57ed9fSAtsushi Murai }
383af57ed9fSAtsushi Murai 
384af57ed9fSAtsushi Murai static void
38530c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
38630c2f2ffSBrian Somers                 struct fsm_decode *dec)
387af57ed9fSAtsushi Murai {
3887308ec68SBrian Somers   /* Deal with incoming data */
389aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
39053c9f6c0SAtsushi Murai   int type, length;
3910053cc58SBrian Somers   int f;
39203036ec7SBrian Somers   const char *end;
393af57ed9fSAtsushi Murai 
394af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
395af57ed9fSAtsushi Murai     type = *cp;
396af57ed9fSAtsushi Murai     length = cp[1];
39703036ec7SBrian Somers 
398d47dceb8SBrian Somers     if (length == 0) {
399dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
400d47dceb8SBrian Somers       break;
401d47dceb8SBrian Somers     }
402d47dceb8SBrian Somers 
40303036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
40403036ec7SBrian Somers       length = sizeof(struct lcp_opt);
405dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
406d47dceb8SBrian Somers                 fp->link->name, length);
40703036ec7SBrian Somers     }
408af57ed9fSAtsushi Murai 
4090053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
4100053cc58SBrian Somers       if (algorithm[f]->id == type)
4110053cc58SBrian Somers         break;
412af57ed9fSAtsushi Murai 
41303036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
41403036ec7SBrian Somers     if (end == NULL)
41503036ec7SBrian Somers       end = "";
41603036ec7SBrian Somers 
41703036ec7SBrian Somers     if (type < NCFTYPES)
418dd7e2610SBrian Somers       log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
41903036ec7SBrian Somers     else
420dd7e2610SBrian Somers       log_Printf(LogCCP, " ???[%d] %s\n", length, end);
42103036ec7SBrian Somers 
4220053cc58SBrian Somers     if (f == -1) {
4230053cc58SBrian Somers       /* Don't understand that :-( */
4240053cc58SBrian Somers       if (mode_type == MODE_REQ) {
42583d1af55SBrian Somers         ccp->my_reject |= (1 << type);
42630c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
42730c2f2ffSBrian Somers         dec->rejend += length;
4280053cc58SBrian Somers       }
4290053cc58SBrian Somers     } else {
43003036ec7SBrian Somers       struct ccp_opt *o;
4310053cc58SBrian Somers 
4329780ef31SBrian Somers       switch (mode_type) {
433af57ed9fSAtsushi Murai       case MODE_REQ:
4341342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
4351342caedSBrian Somers             ccp->in.algorithm == -1) {
43603036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
43703036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4380053cc58SBrian Somers           case MODE_REJ:
43903036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
44003036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4410053cc58SBrian Somers             break;
4420053cc58SBrian Somers           case MODE_NAK:
44303036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
44403036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4450053cc58SBrian Somers             break;
4460053cc58SBrian Somers           case MODE_ACK:
44730c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
44830c2f2ffSBrian Somers 	    dec->ackend += length;
44983d1af55SBrian Somers 	    ccp->his_proto = type;
45003036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4510053cc58SBrian Somers             break;
4520053cc58SBrian Somers           }
453af57ed9fSAtsushi Murai 	} else {
45430c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
45530c2f2ffSBrian Somers 	  dec->rejend += length;
456af57ed9fSAtsushi Murai 	}
457af57ed9fSAtsushi Murai 	break;
458af57ed9fSAtsushi Murai       case MODE_NAK:
45903036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
46003036ec7SBrian Somers           if (o->val.id == cp[0])
46103036ec7SBrian Somers             break;
46203036ec7SBrian Somers         if (o == NULL)
463dd7e2610SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n",
464d47dceb8SBrian Somers                     fp->link->name);
4650053cc58SBrian Somers         else {
46603036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
46703036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
46883d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4691ae349f5Scvs2svn           else {
47083d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
47183d1af55SBrian Somers 	    ccp->my_proto = -1;
4721ae349f5Scvs2svn           }
4730053cc58SBrian Somers         }
4740053cc58SBrian Somers         break;
475af57ed9fSAtsushi Murai       case MODE_REJ:
47683d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
47783d1af55SBrian Somers 	ccp->my_proto = -1;
478af57ed9fSAtsushi Murai 	break;
479af57ed9fSAtsushi Murai       }
480af57ed9fSAtsushi Murai     }
4810053cc58SBrian Somers 
48203036ec7SBrian Somers     plen -= cp[1];
48303036ec7SBrian Somers     cp += cp[1];
484af57ed9fSAtsushi Murai   }
4850053cc58SBrian Somers 
486e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
4871342caedSBrian Somers     if (dec->rejend != dec->rej) {
48803036ec7SBrian Somers       /* rejects are preferred */
48903036ec7SBrian Somers       dec->ackend = dec->ack;
49003036ec7SBrian Somers       dec->nakend = dec->nak;
49103036ec7SBrian Somers       if (ccp->in.state == NULL) {
49283d1af55SBrian Somers         ccp->his_proto = -1;
49303036ec7SBrian Somers         ccp->in.algorithm = -1;
49403036ec7SBrian Somers       }
4951342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
49603036ec7SBrian Somers       /* then NAKs */
49703036ec7SBrian Somers       dec->ackend = dec->ack;
49803036ec7SBrian Somers       if (ccp->in.state == NULL) {
49903036ec7SBrian Somers         ccp->his_proto = -1;
50003036ec7SBrian Somers         ccp->in.algorithm = -1;
501247ab36dSBrian Somers       }
5021ae349f5Scvs2svn     }
5030053cc58SBrian Somers   }
504af57ed9fSAtsushi Murai }
505af57ed9fSAtsushi Murai 
506af57ed9fSAtsushi Murai void
507dd7e2610SBrian Somers ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
508af57ed9fSAtsushi Murai {
5097308ec68SBrian Somers   /* Got PROTO_CCP from link */
510455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
511dd7e2610SBrian Somers     fsm_Input(&ccp->fsm, bp);
512af57ed9fSAtsushi Murai   else {
513641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
514dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
515d47dceb8SBrian Somers                  ccp->fsm.link->name, bundle_PhaseName(bundle));
516dd7e2610SBrian Somers     mbuf_Free(bp);
517af57ed9fSAtsushi Murai   }
518af57ed9fSAtsushi Murai }
5190053cc58SBrian Somers 
520503a7782SBrian Somers static void
521503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5220053cc58SBrian Somers {
5237308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
524f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
525f4768038SBrian Somers 
526f4768038SBrian Somers   if (ccp->reset_sent != -1) {
527f4768038SBrian Somers     if (id != ccp->reset_sent) {
528dd7e2610SBrian Somers       log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)"
529d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
53098baf7c8SBrian Somers       return;
53198baf7c8SBrian Somers     }
53298baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
533f4768038SBrian Somers   } else if (id == ccp->last_reset)
534dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
535d47dceb8SBrian Somers               fp->link->name);
53698baf7c8SBrian Somers   else {
537dd7e2610SBrian Somers     log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n",
538d47dceb8SBrian Somers               fp->link->name, id);
53998baf7c8SBrian Somers     return;
54098baf7c8SBrian Somers   }
54198baf7c8SBrian Somers 
542f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
543f4768038SBrian Somers   ccp->reset_sent = -1;
54403036ec7SBrian Somers   if (ccp->in.state != NULL)
54503036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5460053cc58SBrian Somers }
5470053cc58SBrian Somers 
5480053cc58SBrian Somers int
5493b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
550503a7782SBrian Somers              struct mbuf *m)
5510053cc58SBrian Somers {
5520a1b5c9dSBrian Somers   /*
5530a1b5c9dSBrian Somers    * Compress outgoing data.  It's already deemed to be suitable Network
5540a1b5c9dSBrian Somers    * Layer data.
5550a1b5c9dSBrian Somers    */
5560a1b5c9dSBrian Somers   if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL)
55703036ec7SBrian Somers     return (*algorithm[ccp->out.algorithm]->o.Write)
55803036ec7SBrian Somers              (ccp->out.state, ccp, l, pri, proto, m);
5590053cc58SBrian Somers   return 0;
5600053cc58SBrian Somers }
5610053cc58SBrian Somers 
5620053cc58SBrian Somers struct mbuf *
563503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
5640053cc58SBrian Somers {
565ee6c193fSBrian Somers   /*
566ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
567ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
568ee6c193fSBrian Somers    */
569e43ebac1SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
570ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
5717308ec68SBrian Somers       /* Decompress incoming data */
5722267893fSBrian Somers       if (ccp->reset_sent != -1)
57398baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
574dd7e2610SBrian Somers         fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
5752267893fSBrian Somers       else if (ccp->in.state != NULL)
57603036ec7SBrian Somers         return (*algorithm[ccp->in.algorithm]->i.Read)
57703036ec7SBrian Somers                  (ccp->in.state, ccp, proto, bp);
578dd7e2610SBrian Somers       mbuf_Free(bp);
579ee6c193fSBrian Somers       bp = NULL;
5800a1b5c9dSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL)
581ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
58203036ec7SBrian Somers       (*algorithm[ccp->in.algorithm]->i.DictSetup)
58303036ec7SBrian Somers         (ccp->in.state, ccp, *proto, bp);
5840053cc58SBrian Somers   }
5850053cc58SBrian Somers 
586ee6c193fSBrian Somers   return bp;
5871ae349f5Scvs2svn }
588ed32233cSBrian Somers 
589ed32233cSBrian Somers u_short
590ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
5910053cc58SBrian Somers {
592ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
593ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
5940053cc58SBrian Somers }
5951df0a3b9SBrian Somers 
59606337856SBrian Somers int
5971df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
5981df0a3b9SBrian Somers {
5991df0a3b9SBrian Somers   int f;
6001df0a3b9SBrian Somers 
6011df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
60206337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
6031df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
60406337856SBrian Somers       return 1;
60506337856SBrian Somers     }
6061df0a3b9SBrian Somers 
60706337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
60806337856SBrian Somers 
60906337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
61006337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
61106337856SBrian Somers       return 1;
61206337856SBrian Somers 
61306337856SBrian Somers   return 0;				/* No CCP at all */
6141df0a3b9SBrian Somers }
615