xref: /freebsd/usr.sbin/ppp/ccp.c (revision 9b9967924bb74dae6b202347407043821cd06fa0)
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  *
2097d92980SPeter Wemm  * $FreeBSD$
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>
33eb6e5e05SBrian Somers #include <string.h>	/* memcpy() on some archs */
3485b542cfSBrian Somers #include <termios.h>
3575240ed1SBrian Somers 
365d9e6103SBrian Somers #include "layer.h"
37c9e11a11SBrian Somers #include "defs.h"
38b6e82f33SBrian Somers #include "command.h"
3975240ed1SBrian Somers #include "mbuf.h"
4075240ed1SBrian Somers #include "log.h"
4175240ed1SBrian Somers #include "timer.h"
42af57ed9fSAtsushi Murai #include "fsm.h"
435d9e6103SBrian Somers #include "proto.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"
495a72b6edSBrian Somers #include "lqr.h"
505a72b6edSBrian Somers #include "hdlc.h"
511038894eSBrian Somers #include "lcp.h"
521038894eSBrian Somers #include "ccp.h"
535828db6dSBrian Somers #include "ipcp.h"
545ca5389aSBrian Somers #include "filter.h"
5585b542cfSBrian Somers #include "descriptor.h"
5685b542cfSBrian Somers #include "prompt.h"
57503a7782SBrian Somers #include "link.h"
583b0f8d2eSBrian Somers #include "mp.h"
59ed32233cSBrian Somers #include "async.h"
60ed32233cSBrian Somers #include "physical.h"
61972a1bcfSBrian Somers #ifndef NORADIUS
62972a1bcfSBrian Somers #include "radius.h"
63972a1bcfSBrian Somers #endif
64a8d604abSBrian Somers #ifdef HAVE_DES
65a8d604abSBrian Somers #include "mppe.h"
66a8d604abSBrian Somers #endif
673b0f8d2eSBrian Somers #include "bundle.h"
68af57ed9fSAtsushi Murai 
69927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
702267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
712267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
7230c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
7330c2f2ffSBrian Somers                             struct fsm_decode *);
74927145beSBrian Somers static void CcpLayerStart(struct fsm *);
75927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
766f384573SBrian Somers static int CcpLayerUp(struct fsm *);
77927145beSBrian Somers static void CcpLayerDown(struct fsm *);
78479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int);
79503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
80503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
81af57ed9fSAtsushi Murai 
8283d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
83af57ed9fSAtsushi Murai   CcpLayerUp,
84af57ed9fSAtsushi Murai   CcpLayerDown,
85af57ed9fSAtsushi Murai   CcpLayerStart,
86af57ed9fSAtsushi Murai   CcpLayerFinish,
87af57ed9fSAtsushi Murai   CcpInitRestartCounter,
88af57ed9fSAtsushi Murai   CcpSendConfigReq,
892267893fSBrian Somers   CcpSentTerminateReq,
90af57ed9fSAtsushi Murai   CcpSendTerminateAck,
91af57ed9fSAtsushi Murai   CcpDecodeConfig,
92503a7782SBrian Somers   CcpRecvResetReq,
93503a7782SBrian Somers   CcpRecvResetAck
94af57ed9fSAtsushi Murai };
95af57ed9fSAtsushi Murai 
96182c898aSBrian Somers static const char * const ccp_TimerNames[] =
976f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
986f384573SBrian Somers 
99d6d3eeabSBrian Somers static const char *
100d6d3eeabSBrian Somers protoname(int proto)
101d6d3eeabSBrian Somers {
102182c898aSBrian Somers   static char const * const cftypes[] = {
103d6d3eeabSBrian Somers     /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
1049e836af5SBrian Somers     "OUI",		/* 0: OUI */
1059e836af5SBrian Somers     "PRED1",		/* 1: Predictor type 1 */
1069e836af5SBrian Somers     "PRED2",		/* 2: Predictor type 2 */
1079e836af5SBrian Somers     "PUDDLE",		/* 3: Puddle Jumber */
108d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
109d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
1109e836af5SBrian Somers     "HWPPC",		/* 16: Hewlett-Packard PPC */
1114bc84b8cSBrian Somers     "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
112a8d604abSBrian Somers     "MPPE",		/* 18: Microsoft PPC (rfc2118) and */
113a8d604abSBrian Somers 			/*     Microsoft PPE (draft-ietf-pppext-mppe) */
1144bc84b8cSBrian Somers     "GAND",		/* 19: Gandalf FZA (rfc1993) */
115b6e82f33SBrian Somers     "V42BIS",		/* 20: ARG->DATA.42bis compression */
1160053cc58SBrian Somers     "BSD",		/* 21: BSD LZW Compress */
117d6d3eeabSBrian Somers     NULL,
1184bc84b8cSBrian Somers     "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1194bc84b8cSBrian Somers     "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
1201342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1214bc84b8cSBrian Somers     "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1224bc84b8cSBrian Somers     "DEFLATE",		/* 26: Deflate (rfc1979) */
123af57ed9fSAtsushi Murai   };
124af57ed9fSAtsushi Murai 
125d6d3eeabSBrian Somers   if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes ||
126d6d3eeabSBrian Somers       cftypes[proto] == NULL)
127d6d3eeabSBrian Somers     return HexStr(proto, NULL, 0);
1289e836af5SBrian Somers 
1290053cc58SBrian Somers   return cftypes[proto];
1300053cc58SBrian Somers }
1310053cc58SBrian Somers 
1324bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
133182c898aSBrian Somers static const struct ccp_algorithm * const algorithm[] = {
1344bc84b8cSBrian Somers   &DeflateAlgorithm,
1350053cc58SBrian Somers   &Pred1Algorithm,
1364bc84b8cSBrian Somers   &PppdDeflateAlgorithm
137a8d604abSBrian Somers #ifdef HAVE_DES
138a8d604abSBrian Somers   , &MPPEAlgorithm
139a8d604abSBrian Somers #endif
1400053cc58SBrian Somers };
1410053cc58SBrian Somers 
14270ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1430053cc58SBrian Somers 
144274e766cSBrian Somers int
145503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
146af57ed9fSAtsushi Murai {
147dd0645c5SBrian Somers   struct link *l;
148dd0645c5SBrian Somers   struct ccp *ccp;
149dd0645c5SBrian Somers 
1503a2e4f62SBrian Somers   l = command_ChooseLink(arg);
151dd0645c5SBrian Somers   ccp = &l->ccp;
152503a7782SBrian Somers 
153b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1541e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
1555d9e6103SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
156b6217683SBrian Somers     prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
157503a7782SBrian Somers                   protoname(ccp->my_proto), protoname(ccp->his_proto));
158b6217683SBrian Somers     prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
159503a7782SBrian Somers                   ccp->uncompout, ccp->compout,
160503a7782SBrian Somers                   ccp->compin, ccp->uncompin);
1615d9e6103SBrian Somers   }
162cd9647a1SBrian Somers 
163b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
164479508cfSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
165479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
166479508cfSBrian Somers                 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
167479508cfSBrian Somers                 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
168b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
169b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
170b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1711342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1721342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1731342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1741342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1751342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1761342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
177a8d604abSBrian Somers #ifdef HAVE_DES
178a8d604abSBrian Somers   prompt_Printf(arg->prompt, "           MPPE:       %s\n",
179a8d604abSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
180a8d604abSBrian Somers   prompt_Printf(arg->prompt, "Key Size = %d-bits\n", ccp->cfg.mppe.keybits);
181a8d604abSBrian Somers #endif
182274e766cSBrian Somers   return 0;
183af57ed9fSAtsushi Murai }
184af57ed9fSAtsushi Murai 
1851ae349f5Scvs2svn void
1866f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
187af57ed9fSAtsushi Murai {
1886f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
1896f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
1906f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
1916f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
192ea661041SBrian Somers }
193ea661041SBrian Somers 
194ea661041SBrian Somers void
1956d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1966d666775SBrian Somers          const struct fsm_parent *parent)
197ea661041SBrian Somers {
1987308ec68SBrian Somers   /* Initialise ourselves */
1993b0f8d2eSBrian Somers 
200479508cfSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
2016f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
202cd9647a1SBrian Somers 
20303036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
20403036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
205479508cfSBrian Somers   ccp->cfg.fsm.timeout = DEF_FSMRETRY;
206479508cfSBrian Somers   ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
207479508cfSBrian Somers   ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
2081342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
2091342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
2101342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
211a8d604abSBrian Somers #ifdef HAVE_DES
212a8d604abSBrian Somers   ccp->cfg.mppe.keybits = 128;
213a8d604abSBrian Somers   ccp->cfg.neg[CCP_NEG_MPPE] = 0;
214a8d604abSBrian Somers #endif
215cd9647a1SBrian Somers 
216503a7782SBrian Somers   ccp_Setup(ccp);
217503a7782SBrian Somers }
218503a7782SBrian Somers 
219503a7782SBrian Somers void
220503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
221503a7782SBrian Somers {
222503a7782SBrian Somers   /* Set ourselves up for a startup */
223503a7782SBrian Somers   ccp->fsm.open_mode = 0;
224503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
225503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
22603036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
22703036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
22803036ec7SBrian Somers   ccp->in.opt.id = -1;
22903036ec7SBrian Somers   ccp->out.opt = NULL;
230503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
231503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
232503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
233af57ed9fSAtsushi Murai }
234af57ed9fSAtsushi Murai 
235af57ed9fSAtsushi Murai static void
236479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what)
237af57ed9fSAtsushi Murai {
2387308ec68SBrian Somers   /* Set fsm timer load */
239cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
240cd9647a1SBrian Somers 
241479508cfSBrian Somers   fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
242479508cfSBrian Somers   switch (what) {
243479508cfSBrian Somers     case FSM_REQ_TIMER:
244479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxreq;
245479508cfSBrian Somers       break;
246479508cfSBrian Somers     case FSM_TRM_TIMER:
247479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxtrm;
248479508cfSBrian Somers       break;
249479508cfSBrian Somers     default:
250479508cfSBrian Somers       fp->restart = 1;
251479508cfSBrian Somers       break;
252479508cfSBrian Somers   }
253af57ed9fSAtsushi Murai }
254af57ed9fSAtsushi Murai 
255af57ed9fSAtsushi Murai static void
256944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
257af57ed9fSAtsushi Murai {
2587308ec68SBrian Somers   /* Send config REQ please */
259aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
26003036ec7SBrian Somers   struct ccp_opt **o;
26130c2f2ffSBrian Somers   u_char *cp, buff[100];
26203036ec7SBrian Somers   int f, alloc;
263af57ed9fSAtsushi Murai 
26430c2f2ffSBrian Somers   cp = buff;
26503036ec7SBrian Somers   o = &ccp->out.opt;
26603036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
26783d1af55SBrian Somers   ccp->my_proto = -1;
26803036ec7SBrian Somers   ccp->out.algorithm = -1;
2690053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
2701342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2711342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
2720053cc58SBrian Somers 
273ba081e43SBrian Somers       if (!alloc)
274ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
275ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
276ba081e43SBrian Somers             break;
277ba081e43SBrian Somers 
278ba081e43SBrian Somers       if (alloc || *o == NULL) {
27903036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
28003036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
28103036ec7SBrian Somers         (*o)->val.len = 2;
28203036ec7SBrian Somers         (*o)->next = NULL;
28303036ec7SBrian Somers         (*o)->algorithm = f;
28403036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
285af57ed9fSAtsushi Murai       }
2861ae349f5Scvs2svn 
28703036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
288dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
28930c2f2ffSBrian Somers         break;
29030c2f2ffSBrian Somers       }
2912267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2922267893fSBrian Somers       cp += (*o)->val.len;
29303036ec7SBrian Somers 
29403036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
29503036ec7SBrian Somers       ccp->out.algorithm = f;
29603036ec7SBrian Somers 
29703036ec7SBrian Somers       if (alloc)
29803036ec7SBrian Somers         o = &(*o)->next;
2991ae349f5Scvs2svn     }
3002267893fSBrian Somers 
301411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
302af57ed9fSAtsushi Murai }
303af57ed9fSAtsushi Murai 
304af57ed9fSAtsushi Murai void
305dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
306af57ed9fSAtsushi Murai {
3077308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
308aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3092267893fSBrian Somers 
31083d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
31183d1af55SBrian Somers   ccp->last_reset = -1;
312411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
313af57ed9fSAtsushi Murai }
314af57ed9fSAtsushi Murai 
315af57ed9fSAtsushi Murai static void
3162267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
317af57ed9fSAtsushi Murai {
3187308ec68SBrian Somers   /* Term REQ just sent by FSM */
319af57ed9fSAtsushi Murai }
320af57ed9fSAtsushi Murai 
321af57ed9fSAtsushi Murai static void
3222267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
323af57ed9fSAtsushi Murai {
3247308ec68SBrian Somers   /* Send Term ACK please */
325411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
326af57ed9fSAtsushi Murai }
327af57ed9fSAtsushi Murai 
328503a7782SBrian Somers static void
329944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
330af57ed9fSAtsushi Murai {
3317308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
332aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
33303036ec7SBrian Somers   if (ccp->out.state != NULL)
33403036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
335af57ed9fSAtsushi Murai }
336af57ed9fSAtsushi Murai 
337af57ed9fSAtsushi Murai static void
338944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
339af57ed9fSAtsushi Murai {
3407308ec68SBrian Somers   /* We're about to start up ! */
341479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
342479508cfSBrian Somers 
3433a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
344479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
345af57ed9fSAtsushi Murai }
346af57ed9fSAtsushi Murai 
347af57ed9fSAtsushi Murai static void
348897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
349af57ed9fSAtsushi Murai {
350897f9429SBrian Somers   /* About to come down */
351aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
352ba081e43SBrian Somers   struct ccp_opt *next;
353ba081e43SBrian Somers 
3543a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
35503036ec7SBrian Somers   if (ccp->in.state != NULL) {
35603036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
35703036ec7SBrian Somers     ccp->in.state = NULL;
3588d9b9867SBrian Somers     ccp->in.algorithm = -1;
3597308ec68SBrian Somers   }
36003036ec7SBrian Somers   if (ccp->out.state != NULL) {
36103036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
36203036ec7SBrian Somers     ccp->out.state = NULL;
3638d9b9867SBrian Somers     ccp->out.algorithm = -1;
3647308ec68SBrian Somers   }
3658d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
366ba081e43SBrian Somers 
367ba081e43SBrian Somers   while (ccp->out.opt) {
368ba081e43SBrian Somers     next = ccp->out.opt->next;
369ba081e43SBrian Somers     free(ccp->out.opt);
370ba081e43SBrian Somers     ccp->out.opt = next;
371ba081e43SBrian Somers   }
372897f9429SBrian Somers   ccp_Setup(ccp);
373af57ed9fSAtsushi Murai }
374af57ed9fSAtsushi Murai 
375af57ed9fSAtsushi Murai static void
376897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
377af57ed9fSAtsushi Murai {
378897f9429SBrian Somers   /* We're now down */
3793a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
380af57ed9fSAtsushi Murai }
381af57ed9fSAtsushi Murai 
3823377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
3836f384573SBrian Somers static int
384944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
385af57ed9fSAtsushi Murai {
3867308ec68SBrian Somers   /* We're now up */
387aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
388479508cfSBrian Somers 
3893a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
390479508cfSBrian Somers 
39103036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
39203036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
39303036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
39403036ec7SBrian Somers     if (ccp->in.state == NULL) {
395dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
396d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
39783d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
398dd7e2610SBrian Somers       fsm_Close(fp);
399479508cfSBrian Somers       return 0;
40079d1bdaeSBrian Somers     }
401af57ed9fSAtsushi Murai   }
402af57ed9fSAtsushi Murai 
40303036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
40403036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
40503036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
40603036ec7SBrian Somers                        (&ccp->out.opt->val);
40703036ec7SBrian Somers     if (ccp->out.state == NULL) {
408dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
409d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
41083d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
411dd7e2610SBrian Somers       fsm_Close(fp);
412479508cfSBrian Somers       return 0;
413247ab36dSBrian Somers     }
414af57ed9fSAtsushi Murai   }
415af57ed9fSAtsushi Murai 
416479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
417479508cfSBrian Somers 
418dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
419d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
42083d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
421479508cfSBrian Somers 
4226f384573SBrian Somers   return 1;
423af57ed9fSAtsushi Murai }
424af57ed9fSAtsushi Murai 
425af57ed9fSAtsushi Murai static void
42630c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
42730c2f2ffSBrian Somers                 struct fsm_decode *dec)
428af57ed9fSAtsushi Murai {
4297308ec68SBrian Somers   /* Deal with incoming data */
430aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
43131516407SBrian Somers   int type, length, f;
43203036ec7SBrian Somers   const char *end;
433af57ed9fSAtsushi Murai 
43431516407SBrian Somers   if (mode_type == MODE_REQ)
43531516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
43631516407SBrian Somers 
437af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
438af57ed9fSAtsushi Murai     type = *cp;
439af57ed9fSAtsushi Murai     length = cp[1];
44003036ec7SBrian Somers 
441d47dceb8SBrian Somers     if (length == 0) {
442dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
443d47dceb8SBrian Somers       break;
444d47dceb8SBrian Somers     }
445d47dceb8SBrian Somers 
44603036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
44703036ec7SBrian Somers       length = sizeof(struct lcp_opt);
448dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
449d47dceb8SBrian Somers                 fp->link->name, length);
45003036ec7SBrian Somers     }
451af57ed9fSAtsushi Murai 
4520053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
4530053cc58SBrian Somers       if (algorithm[f]->id == type)
4540053cc58SBrian Somers         break;
455af57ed9fSAtsushi Murai 
45603036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
45703036ec7SBrian Somers     if (end == NULL)
45803036ec7SBrian Somers       end = "";
45903036ec7SBrian Somers 
460d6d3eeabSBrian Somers     log_Printf(LogCCP, " %s[%d] %s\n", protoname(type), length, end);
46103036ec7SBrian Somers 
4620053cc58SBrian Somers     if (f == -1) {
4630053cc58SBrian Somers       /* Don't understand that :-( */
4640053cc58SBrian Somers       if (mode_type == MODE_REQ) {
46583d1af55SBrian Somers         ccp->my_reject |= (1 << type);
46630c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
46730c2f2ffSBrian Somers         dec->rejend += length;
4680053cc58SBrian Somers       }
4690053cc58SBrian Somers     } else {
47003036ec7SBrian Somers       struct ccp_opt *o;
4710053cc58SBrian Somers 
4729780ef31SBrian Somers       switch (mode_type) {
473af57ed9fSAtsushi Murai       case MODE_REQ:
4741342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
4751342caedSBrian Somers             ccp->in.algorithm == -1) {
47603036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
47703036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4780053cc58SBrian Somers           case MODE_REJ:
47903036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
48003036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4810053cc58SBrian Somers             break;
4820053cc58SBrian Somers           case MODE_NAK:
48303036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
48403036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4850053cc58SBrian Somers             break;
4860053cc58SBrian Somers           case MODE_ACK:
48730c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
48830c2f2ffSBrian Somers 	    dec->ackend += length;
48983d1af55SBrian Somers 	    ccp->his_proto = type;
49003036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4910053cc58SBrian Somers             break;
4920053cc58SBrian Somers           }
493af57ed9fSAtsushi Murai 	} else {
49430c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
49530c2f2ffSBrian Somers 	  dec->rejend += length;
496af57ed9fSAtsushi Murai 	}
497af57ed9fSAtsushi Murai 	break;
498af57ed9fSAtsushi Murai       case MODE_NAK:
49903036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
50003036ec7SBrian Somers           if (o->val.id == cp[0])
50103036ec7SBrian Somers             break;
50203036ec7SBrian Somers         if (o == NULL)
5039b996792SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
5049b996792SBrian Somers                      " option\n", fp->link->name);
5050053cc58SBrian Somers         else {
50603036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
50703036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
50883d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
5091ae349f5Scvs2svn           else {
51083d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
51183d1af55SBrian Somers 	    ccp->my_proto = -1;
5121ae349f5Scvs2svn           }
5130053cc58SBrian Somers         }
5140053cc58SBrian Somers         break;
515af57ed9fSAtsushi Murai       case MODE_REJ:
51683d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
51783d1af55SBrian Somers 	ccp->my_proto = -1;
518af57ed9fSAtsushi Murai 	break;
519af57ed9fSAtsushi Murai       }
520af57ed9fSAtsushi Murai     }
5210053cc58SBrian Somers 
52203036ec7SBrian Somers     plen -= cp[1];
52303036ec7SBrian Somers     cp += cp[1];
524af57ed9fSAtsushi Murai   }
5250053cc58SBrian Somers 
526e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
5271342caedSBrian Somers     if (dec->rejend != dec->rej) {
52803036ec7SBrian Somers       /* rejects are preferred */
52903036ec7SBrian Somers       dec->ackend = dec->ack;
53003036ec7SBrian Somers       dec->nakend = dec->nak;
53103036ec7SBrian Somers       if (ccp->in.state == NULL) {
53283d1af55SBrian Somers         ccp->his_proto = -1;
53303036ec7SBrian Somers         ccp->in.algorithm = -1;
53403036ec7SBrian Somers       }
5351342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
53603036ec7SBrian Somers       /* then NAKs */
53703036ec7SBrian Somers       dec->ackend = dec->ack;
53803036ec7SBrian Somers       if (ccp->in.state == NULL) {
53903036ec7SBrian Somers         ccp->his_proto = -1;
54003036ec7SBrian Somers         ccp->in.algorithm = -1;
541247ab36dSBrian Somers       }
5421ae349f5Scvs2svn     }
5430053cc58SBrian Somers   }
544af57ed9fSAtsushi Murai }
545af57ed9fSAtsushi Murai 
5465d9e6103SBrian Somers extern struct mbuf *
5475d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
548af57ed9fSAtsushi Murai {
5497308ec68SBrian Somers   /* Got PROTO_CCP from link */
55026af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
551455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
5525d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
553af57ed9fSAtsushi Murai   else {
554641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
555dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
5565d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
55726af0ae9SBrian Somers     m_freem(bp);
558af57ed9fSAtsushi Murai   }
5595d9e6103SBrian Somers   return NULL;
560af57ed9fSAtsushi Murai }
5610053cc58SBrian Somers 
562503a7782SBrian Somers static void
563503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5640053cc58SBrian Somers {
5657308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
566f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
567f4768038SBrian Somers 
568f4768038SBrian Somers   if (ccp->reset_sent != -1) {
569f4768038SBrian Somers     if (id != ccp->reset_sent) {
570a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
571d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
57298baf7c8SBrian Somers       return;
57398baf7c8SBrian Somers     }
57498baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
575f4768038SBrian Somers   } else if (id == ccp->last_reset)
576dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
577d47dceb8SBrian Somers                fp->link->name);
57898baf7c8SBrian Somers   else {
579a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
580d47dceb8SBrian Somers                fp->link->name, id);
58198baf7c8SBrian Somers     return;
58298baf7c8SBrian Somers   }
58398baf7c8SBrian Somers 
584f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
585f4768038SBrian Somers   ccp->reset_sent = -1;
58603036ec7SBrian Somers   if (ccp->in.state != NULL)
58703036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5880053cc58SBrian Somers }
5890053cc58SBrian Somers 
5905d9e6103SBrian Somers static struct mbuf *
5915d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
5925d9e6103SBrian Somers               int pri, u_short *proto)
5930053cc58SBrian Somers {
5945d9e6103SBrian Somers   if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED &&
595411675baSBrian Somers       l->ccp.out.state != NULL) {
596411675baSBrian Somers     bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
5975d9e6103SBrian Somers            (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
598411675baSBrian Somers     switch (*proto) {
599411675baSBrian Somers       case PROTO_ICOMPD:
60026af0ae9SBrian Somers         m_settype(bp, MB_ICOMPDOUT);
601411675baSBrian Somers         break;
602411675baSBrian Somers       case PROTO_COMPD:
60326af0ae9SBrian Somers         m_settype(bp, MB_COMPDOUT);
604411675baSBrian Somers         break;
605411675baSBrian Somers     }
606411675baSBrian Somers   }
6075d9e6103SBrian Somers 
6085d9e6103SBrian Somers   return bp;
6090053cc58SBrian Somers }
6100053cc58SBrian Somers 
6115d9e6103SBrian Somers static struct mbuf *
6125d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
6130053cc58SBrian Somers {
614ee6c193fSBrian Somers   /*
615ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
616ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
617ee6c193fSBrian Somers    */
6185d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
619ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
6206815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n",
6216815097bSBrian Somers                  *proto == PROTO_ICOMPD ? "I" : "");
6227308ec68SBrian Somers       /* Decompress incoming data */
6235d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
62498baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
625411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
626411675baSBrian Somers                    MB_CCPOUT);
627411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
628411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
6295d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
630411675baSBrian Somers         switch (*proto) {
631411675baSBrian Somers           case PROTO_ICOMPD:
63226af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
633411675baSBrian Somers             break;
634411675baSBrian Somers           case PROTO_COMPD:
63526af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
636411675baSBrian Somers             break;
637411675baSBrian Somers         }
638411675baSBrian Somers         return bp;
639411675baSBrian Somers       }
64026af0ae9SBrian Somers       m_freem(bp);
641ee6c193fSBrian Somers       bp = NULL;
6426815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
6436815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n");
644ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
6455d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
6465d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
6476815097bSBrian Somers     } else
6486815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n");
6490053cc58SBrian Somers   }
6500053cc58SBrian Somers 
651ee6c193fSBrian Somers   return bp;
6521ae349f5Scvs2svn }
653ed32233cSBrian Somers 
654ed32233cSBrian Somers u_short
655ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
6560053cc58SBrian Somers {
657ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
658ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
6590053cc58SBrian Somers }
6601df0a3b9SBrian Somers 
66106337856SBrian Somers int
6621df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
6631df0a3b9SBrian Somers {
6641df0a3b9SBrian Somers   int f;
6651df0a3b9SBrian Somers 
6661df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
66706337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
6681df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
66906337856SBrian Somers       return 1;
67006337856SBrian Somers     }
6711df0a3b9SBrian Somers 
67206337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
67306337856SBrian Somers 
67406337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
67506337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
67606337856SBrian Somers       return 1;
67706337856SBrian Somers 
67806337856SBrian Somers   return 0;				/* No CCP at all */
6791df0a3b9SBrian Somers }
6805d9e6103SBrian Somers 
6815d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
682