xref: /freebsd/usr.sbin/ppp/ccp.c (revision 65309e5cda5d671cbca4763b481566ce387dcf7e)
165309e5cSBrian Somers /*-
265309e5cSBrian Somers  * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
365309e5cSBrian Somers  *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
465309e5cSBrian Somers  *                           Internet Initiative Japan, Inc (IIJ)
565309e5cSBrian Somers  * All rights reserved.
6af57ed9fSAtsushi Murai  *
765309e5cSBrian Somers  * Redistribution and use in source and binary forms, with or without
865309e5cSBrian Somers  * modification, are permitted provided that the following conditions
965309e5cSBrian Somers  * are met:
1065309e5cSBrian Somers  * 1. Redistributions of source code must retain the above copyright
1165309e5cSBrian Somers  *    notice, this list of conditions and the following disclaimer.
1265309e5cSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
1365309e5cSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
1465309e5cSBrian Somers  *    documentation and/or other materials provided with the distribution.
15af57ed9fSAtsushi Murai  *
1665309e5cSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1765309e5cSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1865309e5cSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1965309e5cSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2065309e5cSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2165309e5cSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2265309e5cSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2365309e5cSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2465309e5cSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2565309e5cSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2665309e5cSBrian Somers  * SUCH DAMAGE.
27af57ed9fSAtsushi Murai  *
2897d92980SPeter Wemm  * $FreeBSD$
29af57ed9fSAtsushi Murai  */
3065309e5cSBrian Somers 
31972a1bcfSBrian Somers #include <sys/param.h>
3275240ed1SBrian Somers #include <netinet/in.h>
33eaa4df37SBrian Somers #include <netinet/in_systm.h>
34eaa4df37SBrian Somers #include <netinet/ip.h>
351fa665f5SBrian Somers #include <sys/un.h>
3675240ed1SBrian Somers 
3775240ed1SBrian Somers #include <stdio.h>
3803036ec7SBrian Somers #include <stdlib.h>
39eb6e5e05SBrian Somers #include <string.h>	/* memcpy() on some archs */
4085b542cfSBrian Somers #include <termios.h>
4175240ed1SBrian Somers 
425d9e6103SBrian Somers #include "layer.h"
43c9e11a11SBrian Somers #include "defs.h"
44b6e82f33SBrian Somers #include "command.h"
4575240ed1SBrian Somers #include "mbuf.h"
4675240ed1SBrian Somers #include "log.h"
4775240ed1SBrian Somers #include "timer.h"
48af57ed9fSAtsushi Murai #include "fsm.h"
495d9e6103SBrian Somers #include "proto.h"
50ed6a16c1SPoul-Henning Kamp #include "pred.h"
510053cc58SBrian Somers #include "deflate.h"
525828db6dSBrian Somers #include "throughput.h"
535828db6dSBrian Somers #include "iplist.h"
54eaa4df37SBrian Somers #include "slcompress.h"
555a72b6edSBrian Somers #include "lqr.h"
565a72b6edSBrian Somers #include "hdlc.h"
571038894eSBrian Somers #include "lcp.h"
581038894eSBrian Somers #include "ccp.h"
595828db6dSBrian Somers #include "ipcp.h"
605ca5389aSBrian Somers #include "filter.h"
6185b542cfSBrian Somers #include "descriptor.h"
6285b542cfSBrian Somers #include "prompt.h"
63503a7782SBrian Somers #include "link.h"
643b0f8d2eSBrian Somers #include "mp.h"
65ed32233cSBrian Somers #include "async.h"
66ed32233cSBrian Somers #include "physical.h"
67972a1bcfSBrian Somers #ifndef NORADIUS
68972a1bcfSBrian Somers #include "radius.h"
69972a1bcfSBrian Somers #endif
70a8d604abSBrian Somers #ifdef HAVE_DES
71a8d604abSBrian Somers #include "mppe.h"
72a8d604abSBrian Somers #endif
733b0f8d2eSBrian Somers #include "bundle.h"
74af57ed9fSAtsushi Murai 
75927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
762267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
772267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
7830c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
7930c2f2ffSBrian Somers                             struct fsm_decode *);
80927145beSBrian Somers static void CcpLayerStart(struct fsm *);
81927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
826f384573SBrian Somers static int CcpLayerUp(struct fsm *);
83927145beSBrian Somers static void CcpLayerDown(struct fsm *);
84479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int);
85503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
86503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
87af57ed9fSAtsushi Murai 
8883d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
89af57ed9fSAtsushi Murai   CcpLayerUp,
90af57ed9fSAtsushi Murai   CcpLayerDown,
91af57ed9fSAtsushi Murai   CcpLayerStart,
92af57ed9fSAtsushi Murai   CcpLayerFinish,
93af57ed9fSAtsushi Murai   CcpInitRestartCounter,
94af57ed9fSAtsushi Murai   CcpSendConfigReq,
952267893fSBrian Somers   CcpSentTerminateReq,
96af57ed9fSAtsushi Murai   CcpSendTerminateAck,
97af57ed9fSAtsushi Murai   CcpDecodeConfig,
98503a7782SBrian Somers   CcpRecvResetReq,
99503a7782SBrian Somers   CcpRecvResetAck
100af57ed9fSAtsushi Murai };
101af57ed9fSAtsushi Murai 
102182c898aSBrian Somers static const char * const ccp_TimerNames[] =
1036f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
1046f384573SBrian Somers 
105d6d3eeabSBrian Somers static const char *
106d6d3eeabSBrian Somers protoname(int proto)
107d6d3eeabSBrian Somers {
108182c898aSBrian Somers   static char const * const cftypes[] = {
109d6d3eeabSBrian Somers     /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
1109e836af5SBrian Somers     "OUI",		/* 0: OUI */
1119e836af5SBrian Somers     "PRED1",		/* 1: Predictor type 1 */
1129e836af5SBrian Somers     "PRED2",		/* 2: Predictor type 2 */
1139e836af5SBrian Somers     "PUDDLE",		/* 3: Puddle Jumber */
114d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
115d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
1169e836af5SBrian Somers     "HWPPC",		/* 16: Hewlett-Packard PPC */
1174bc84b8cSBrian Somers     "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
118a8d604abSBrian Somers     "MPPE",		/* 18: Microsoft PPC (rfc2118) and */
119a8d604abSBrian Somers 			/*     Microsoft PPE (draft-ietf-pppext-mppe) */
1204bc84b8cSBrian Somers     "GAND",		/* 19: Gandalf FZA (rfc1993) */
121b6e82f33SBrian Somers     "V42BIS",		/* 20: ARG->DATA.42bis compression */
1220053cc58SBrian Somers     "BSD",		/* 21: BSD LZW Compress */
123d6d3eeabSBrian Somers     NULL,
1244bc84b8cSBrian Somers     "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1254bc84b8cSBrian Somers     "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
1261342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1274bc84b8cSBrian Somers     "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1284bc84b8cSBrian Somers     "DEFLATE",		/* 26: Deflate (rfc1979) */
129af57ed9fSAtsushi Murai   };
130af57ed9fSAtsushi Murai 
131d6d3eeabSBrian Somers   if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes ||
132d6d3eeabSBrian Somers       cftypes[proto] == NULL)
133d6d3eeabSBrian Somers     return HexStr(proto, NULL, 0);
1349e836af5SBrian Somers 
1350053cc58SBrian Somers   return cftypes[proto];
1360053cc58SBrian Somers }
1370053cc58SBrian Somers 
1384bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
139182c898aSBrian Somers static const struct ccp_algorithm * const algorithm[] = {
1404bc84b8cSBrian Somers   &DeflateAlgorithm,
1410053cc58SBrian Somers   &Pred1Algorithm,
1424bc84b8cSBrian Somers   &PppdDeflateAlgorithm
143a8d604abSBrian Somers #ifdef HAVE_DES
144a8d604abSBrian Somers   , &MPPEAlgorithm
145a8d604abSBrian Somers #endif
1460053cc58SBrian Somers };
1470053cc58SBrian Somers 
14870ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1490053cc58SBrian Somers 
150274e766cSBrian Somers int
151503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
152af57ed9fSAtsushi Murai {
153dd0645c5SBrian Somers   struct link *l;
154dd0645c5SBrian Somers   struct ccp *ccp;
155dd0645c5SBrian Somers 
1563a2e4f62SBrian Somers   l = command_ChooseLink(arg);
157dd0645c5SBrian Somers   ccp = &l->ccp;
158503a7782SBrian Somers 
159b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1601e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
1615d9e6103SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
162b6217683SBrian Somers     prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
163503a7782SBrian Somers                   protoname(ccp->my_proto), protoname(ccp->his_proto));
164b6217683SBrian Somers     prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
165503a7782SBrian Somers                   ccp->uncompout, ccp->compout,
166503a7782SBrian Somers                   ccp->compin, ccp->uncompin);
1675d9e6103SBrian Somers   }
168cd9647a1SBrian Somers 
169b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
170479508cfSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
171479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
172479508cfSBrian Somers                 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
173479508cfSBrian Somers                 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
174b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
175b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
176b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1771342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1781342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1791342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1801342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1811342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1821342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
183a8d604abSBrian Somers #ifdef HAVE_DES
184ba6fcad9SBrian Somers   prompt_Printf(arg->prompt, "           MPPE:       %s",
185a8d604abSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
186ba6fcad9SBrian Somers   prompt_Printf(arg->prompt, " (Key Size = %d-bits)\n", ccp->cfg.mppe.keybits);
187a8d604abSBrian Somers #endif
188274e766cSBrian Somers   return 0;
189af57ed9fSAtsushi Murai }
190af57ed9fSAtsushi Murai 
1911ae349f5Scvs2svn void
1926f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
193af57ed9fSAtsushi Murai {
1946f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
1956f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
1966f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
1976f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
198ea661041SBrian Somers }
199ea661041SBrian Somers 
200ea661041SBrian Somers void
2016d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
2026d666775SBrian Somers          const struct fsm_parent *parent)
203ea661041SBrian Somers {
2047308ec68SBrian Somers   /* Initialise ourselves */
2053b0f8d2eSBrian Somers 
206479508cfSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
2076f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
208cd9647a1SBrian Somers 
20903036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
21003036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
211479508cfSBrian Somers   ccp->cfg.fsm.timeout = DEF_FSMRETRY;
212479508cfSBrian Somers   ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
213479508cfSBrian Somers   ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
2141342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
2151342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
2161342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
217a8d604abSBrian Somers #ifdef HAVE_DES
218a8d604abSBrian Somers   ccp->cfg.mppe.keybits = 128;
219385167a6SBrian Somers   ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
220a8d604abSBrian Somers #endif
221cd9647a1SBrian Somers 
222503a7782SBrian Somers   ccp_Setup(ccp);
223503a7782SBrian Somers }
224503a7782SBrian Somers 
225503a7782SBrian Somers void
226503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
227503a7782SBrian Somers {
228503a7782SBrian Somers   /* Set ourselves up for a startup */
229503a7782SBrian Somers   ccp->fsm.open_mode = 0;
230503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
231503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
23203036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
23303036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
23403036ec7SBrian Somers   ccp->in.opt.id = -1;
23503036ec7SBrian Somers   ccp->out.opt = NULL;
236503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
237503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
238503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
239af57ed9fSAtsushi Murai }
240af57ed9fSAtsushi Murai 
241af57ed9fSAtsushi Murai static void
242479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what)
243af57ed9fSAtsushi Murai {
2447308ec68SBrian Somers   /* Set fsm timer load */
245cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
246cd9647a1SBrian Somers 
247479508cfSBrian Somers   fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
248479508cfSBrian Somers   switch (what) {
249479508cfSBrian Somers     case FSM_REQ_TIMER:
250479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxreq;
251479508cfSBrian Somers       break;
252479508cfSBrian Somers     case FSM_TRM_TIMER:
253479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxtrm;
254479508cfSBrian Somers       break;
255479508cfSBrian Somers     default:
256479508cfSBrian Somers       fp->restart = 1;
257479508cfSBrian Somers       break;
258479508cfSBrian Somers   }
259af57ed9fSAtsushi Murai }
260af57ed9fSAtsushi Murai 
261af57ed9fSAtsushi Murai static void
262944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
263af57ed9fSAtsushi Murai {
2647308ec68SBrian Somers   /* Send config REQ please */
265aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
26603036ec7SBrian Somers   struct ccp_opt **o;
26730c2f2ffSBrian Somers   u_char *cp, buff[100];
26803036ec7SBrian Somers   int f, alloc;
269af57ed9fSAtsushi Murai 
27030c2f2ffSBrian Somers   cp = buff;
27103036ec7SBrian Somers   o = &ccp->out.opt;
27203036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
27383d1af55SBrian Somers   ccp->my_proto = -1;
27403036ec7SBrian Somers   ccp->out.algorithm = -1;
2750053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
2761342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2777f89db65SBrian Somers         !REJECTED(ccp, algorithm[f]->id) &&
2787f89db65SBrian Somers         (*algorithm[f]->Usable)(fp)) {
2790053cc58SBrian Somers 
280ba081e43SBrian Somers       if (!alloc)
281ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
282ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
283ba081e43SBrian Somers             break;
284ba081e43SBrian Somers 
285ba081e43SBrian Somers       if (alloc || *o == NULL) {
28603036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
28703036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
28803036ec7SBrian Somers         (*o)->val.len = 2;
28903036ec7SBrian Somers         (*o)->next = NULL;
29003036ec7SBrian Somers         (*o)->algorithm = f;
29103036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
292af57ed9fSAtsushi Murai       }
2931ae349f5Scvs2svn 
29403036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
295dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
29630c2f2ffSBrian Somers         break;
29730c2f2ffSBrian Somers       }
2982267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2992267893fSBrian Somers       cp += (*o)->val.len;
30003036ec7SBrian Somers 
30103036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
30203036ec7SBrian Somers       ccp->out.algorithm = f;
30303036ec7SBrian Somers 
30403036ec7SBrian Somers       if (alloc)
30503036ec7SBrian Somers         o = &(*o)->next;
3061ae349f5Scvs2svn     }
3072267893fSBrian Somers 
308411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
309af57ed9fSAtsushi Murai }
310af57ed9fSAtsushi Murai 
311af57ed9fSAtsushi Murai void
312dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
313af57ed9fSAtsushi Murai {
3147308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
315aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3162267893fSBrian Somers 
31783d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
31883d1af55SBrian Somers   ccp->last_reset = -1;
319411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
320af57ed9fSAtsushi Murai }
321af57ed9fSAtsushi Murai 
322af57ed9fSAtsushi Murai static void
3232267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
324af57ed9fSAtsushi Murai {
3257308ec68SBrian Somers   /* Term REQ just sent by FSM */
326af57ed9fSAtsushi Murai }
327af57ed9fSAtsushi Murai 
328af57ed9fSAtsushi Murai static void
3292267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
330af57ed9fSAtsushi Murai {
3317308ec68SBrian Somers   /* Send Term ACK please */
332411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
333af57ed9fSAtsushi Murai }
334af57ed9fSAtsushi Murai 
335503a7782SBrian Somers static void
336944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
337af57ed9fSAtsushi Murai {
3387308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
339aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
34003036ec7SBrian Somers   if (ccp->out.state != NULL)
34103036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
342af57ed9fSAtsushi Murai }
343af57ed9fSAtsushi Murai 
344af57ed9fSAtsushi Murai static void
345944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
346af57ed9fSAtsushi Murai {
3477308ec68SBrian Somers   /* We're about to start up ! */
348479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
349479508cfSBrian Somers 
3503a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
351479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
352af57ed9fSAtsushi Murai }
353af57ed9fSAtsushi Murai 
354af57ed9fSAtsushi Murai static void
355897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
356af57ed9fSAtsushi Murai {
357897f9429SBrian Somers   /* About to come down */
358aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
359ba081e43SBrian Somers   struct ccp_opt *next;
360ba081e43SBrian Somers 
3613a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
36203036ec7SBrian Somers   if (ccp->in.state != NULL) {
36303036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
36403036ec7SBrian Somers     ccp->in.state = NULL;
3658d9b9867SBrian Somers     ccp->in.algorithm = -1;
3667308ec68SBrian Somers   }
36703036ec7SBrian Somers   if (ccp->out.state != NULL) {
36803036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
36903036ec7SBrian Somers     ccp->out.state = NULL;
3708d9b9867SBrian Somers     ccp->out.algorithm = -1;
3717308ec68SBrian Somers   }
3728d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
373ba081e43SBrian Somers 
374ba081e43SBrian Somers   while (ccp->out.opt) {
375ba081e43SBrian Somers     next = ccp->out.opt->next;
376ba081e43SBrian Somers     free(ccp->out.opt);
377ba081e43SBrian Somers     ccp->out.opt = next;
378ba081e43SBrian Somers   }
379897f9429SBrian Somers   ccp_Setup(ccp);
380af57ed9fSAtsushi Murai }
381af57ed9fSAtsushi Murai 
382af57ed9fSAtsushi Murai static void
383897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
384af57ed9fSAtsushi Murai {
385897f9429SBrian Somers   /* We're now down */
386e1e8b15eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
387e1e8b15eSBrian Somers   struct ccp_opt *next;
388e1e8b15eSBrian Somers 
3893a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
390e1e8b15eSBrian Somers 
391e1e8b15eSBrian Somers   /*
392e1e8b15eSBrian Somers    * Nuke options that may be left over from sending a REQ but never
393e1e8b15eSBrian Somers    * coming up.
394e1e8b15eSBrian Somers    */
395e1e8b15eSBrian Somers   while (ccp->out.opt) {
396e1e8b15eSBrian Somers     next = ccp->out.opt->next;
397e1e8b15eSBrian Somers     free(ccp->out.opt);
398e1e8b15eSBrian Somers     ccp->out.opt = next;
399e1e8b15eSBrian Somers   }
400af57ed9fSAtsushi Murai }
401af57ed9fSAtsushi Murai 
4023377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
4036f384573SBrian Somers static int
404944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
405af57ed9fSAtsushi Murai {
4067308ec68SBrian Somers   /* We're now up */
407aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
408e1e8b15eSBrian Somers   struct ccp_opt **o;
409e1e8b15eSBrian Somers   int f;
410479508cfSBrian Somers 
4113a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
412479508cfSBrian Somers 
41303036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
41403036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
41503036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
41603036ec7SBrian Somers     if (ccp->in.state == NULL) {
417dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
418d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
41983d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
420dd7e2610SBrian Somers       fsm_Close(fp);
421479508cfSBrian Somers       return 0;
42279d1bdaeSBrian Somers     }
423af57ed9fSAtsushi Murai   }
424af57ed9fSAtsushi Murai 
425e1e8b15eSBrian Somers   o = &ccp->out.opt;
426e1e8b15eSBrian Somers   for (f = 0; f < ccp->out.algorithm; f++)
427e1e8b15eSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
428e1e8b15eSBrian Somers       o = &(*o)->next;
429e1e8b15eSBrian Somers 
43003036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
43103036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
432e1e8b15eSBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)(&(*o)->val);
43303036ec7SBrian Somers     if (ccp->out.state == NULL) {
434dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
435d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
43683d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
437dd7e2610SBrian Somers       fsm_Close(fp);
438479508cfSBrian Somers       return 0;
439247ab36dSBrian Somers     }
440af57ed9fSAtsushi Murai   }
441af57ed9fSAtsushi Murai 
442479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
443479508cfSBrian Somers 
444dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
445d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
44683d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
447479508cfSBrian Somers 
4486f384573SBrian Somers   return 1;
449af57ed9fSAtsushi Murai }
450af57ed9fSAtsushi Murai 
451af57ed9fSAtsushi Murai static void
45230c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
45330c2f2ffSBrian Somers                 struct fsm_decode *dec)
454af57ed9fSAtsushi Murai {
4557308ec68SBrian Somers   /* Deal with incoming data */
456aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
45731516407SBrian Somers   int type, length, f;
45803036ec7SBrian Somers   const char *end;
459af57ed9fSAtsushi Murai 
46031516407SBrian Somers   if (mode_type == MODE_REQ)
46131516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
46231516407SBrian Somers 
463af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
464af57ed9fSAtsushi Murai     type = *cp;
465af57ed9fSAtsushi Murai     length = cp[1];
46603036ec7SBrian Somers 
467d47dceb8SBrian Somers     if (length == 0) {
468dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
469d47dceb8SBrian Somers       break;
470d47dceb8SBrian Somers     }
471d47dceb8SBrian Somers 
47203036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
47303036ec7SBrian Somers       length = sizeof(struct lcp_opt);
474dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
475d47dceb8SBrian Somers                 fp->link->name, length);
47603036ec7SBrian Somers     }
477af57ed9fSAtsushi Murai 
4780053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
4790053cc58SBrian Somers       if (algorithm[f]->id == type)
4800053cc58SBrian Somers         break;
481af57ed9fSAtsushi Murai 
48203036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
48303036ec7SBrian Somers     if (end == NULL)
48403036ec7SBrian Somers       end = "";
48503036ec7SBrian Somers 
486d6d3eeabSBrian Somers     log_Printf(LogCCP, " %s[%d] %s\n", protoname(type), length, end);
48703036ec7SBrian Somers 
4880053cc58SBrian Somers     if (f == -1) {
4890053cc58SBrian Somers       /* Don't understand that :-( */
4900053cc58SBrian Somers       if (mode_type == MODE_REQ) {
49183d1af55SBrian Somers         ccp->my_reject |= (1 << type);
49230c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
49330c2f2ffSBrian Somers         dec->rejend += length;
4940053cc58SBrian Somers       }
4950053cc58SBrian Somers     } else {
49603036ec7SBrian Somers       struct ccp_opt *o;
4970053cc58SBrian Somers 
4989780ef31SBrian Somers       switch (mode_type) {
499af57ed9fSAtsushi Murai       case MODE_REQ:
5001342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
5017f89db65SBrian Somers             (*algorithm[f]->Usable)(fp) &&
5021342caedSBrian Somers             ccp->in.algorithm == -1) {
50303036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
50403036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
5050053cc58SBrian Somers           case MODE_REJ:
50603036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
50703036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
5080053cc58SBrian Somers             break;
5090053cc58SBrian Somers           case MODE_NAK:
51003036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
51103036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
5120053cc58SBrian Somers             break;
5130053cc58SBrian Somers           case MODE_ACK:
51430c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
51530c2f2ffSBrian Somers 	    dec->ackend += length;
51683d1af55SBrian Somers 	    ccp->his_proto = type;
51703036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
5180053cc58SBrian Somers             break;
5190053cc58SBrian Somers           }
520af57ed9fSAtsushi Murai 	} else {
52130c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
52230c2f2ffSBrian Somers 	  dec->rejend += length;
523af57ed9fSAtsushi Murai 	}
524af57ed9fSAtsushi Murai 	break;
525af57ed9fSAtsushi Murai       case MODE_NAK:
52603036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
52703036ec7SBrian Somers           if (o->val.id == cp[0])
52803036ec7SBrian Somers             break;
52903036ec7SBrian Somers         if (o == NULL)
5309b996792SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
5319b996792SBrian Somers                      " option\n", fp->link->name);
5320053cc58SBrian Somers         else {
53303036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
53403036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
53583d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
5361ae349f5Scvs2svn           else {
53783d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
53883d1af55SBrian Somers 	    ccp->my_proto = -1;
5391ae349f5Scvs2svn           }
5400053cc58SBrian Somers         }
5410053cc58SBrian Somers         break;
542af57ed9fSAtsushi Murai       case MODE_REJ:
54383d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
54483d1af55SBrian Somers 	ccp->my_proto = -1;
545af57ed9fSAtsushi Murai 	break;
546af57ed9fSAtsushi Murai       }
547af57ed9fSAtsushi Murai     }
5480053cc58SBrian Somers 
54903036ec7SBrian Somers     plen -= cp[1];
55003036ec7SBrian Somers     cp += cp[1];
551af57ed9fSAtsushi Murai   }
5520053cc58SBrian Somers 
553e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
5541342caedSBrian Somers     if (dec->rejend != dec->rej) {
55503036ec7SBrian Somers       /* rejects are preferred */
55603036ec7SBrian Somers       dec->ackend = dec->ack;
55703036ec7SBrian Somers       dec->nakend = dec->nak;
55803036ec7SBrian Somers       if (ccp->in.state == NULL) {
55983d1af55SBrian Somers         ccp->his_proto = -1;
56003036ec7SBrian Somers         ccp->in.algorithm = -1;
56103036ec7SBrian Somers       }
5621342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
56303036ec7SBrian Somers       /* then NAKs */
56403036ec7SBrian Somers       dec->ackend = dec->ack;
56503036ec7SBrian Somers       if (ccp->in.state == NULL) {
56603036ec7SBrian Somers         ccp->his_proto = -1;
56703036ec7SBrian Somers         ccp->in.algorithm = -1;
568247ab36dSBrian Somers       }
5691ae349f5Scvs2svn     }
5700053cc58SBrian Somers   }
571af57ed9fSAtsushi Murai }
572af57ed9fSAtsushi Murai 
5735d9e6103SBrian Somers extern struct mbuf *
5745d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
575af57ed9fSAtsushi Murai {
5767308ec68SBrian Somers   /* Got PROTO_CCP from link */
57726af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
578455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
5795d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
580af57ed9fSAtsushi Murai   else {
581641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
582dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
5835d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
58426af0ae9SBrian Somers     m_freem(bp);
585af57ed9fSAtsushi Murai   }
5865d9e6103SBrian Somers   return NULL;
587af57ed9fSAtsushi Murai }
5880053cc58SBrian Somers 
589503a7782SBrian Somers static void
590503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5910053cc58SBrian Somers {
5927308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
593f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
594f4768038SBrian Somers 
595f4768038SBrian Somers   if (ccp->reset_sent != -1) {
596f4768038SBrian Somers     if (id != ccp->reset_sent) {
597a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
598d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
59998baf7c8SBrian Somers       return;
60098baf7c8SBrian Somers     }
60198baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
602f4768038SBrian Somers   } else if (id == ccp->last_reset)
603dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
604d47dceb8SBrian Somers                fp->link->name);
60598baf7c8SBrian Somers   else {
606a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
607d47dceb8SBrian Somers                fp->link->name, id);
60898baf7c8SBrian Somers     return;
60998baf7c8SBrian Somers   }
61098baf7c8SBrian Somers 
611f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
612f4768038SBrian Somers   ccp->reset_sent = -1;
61303036ec7SBrian Somers   if (ccp->in.state != NULL)
61403036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
6150053cc58SBrian Somers }
6160053cc58SBrian Somers 
6175d9e6103SBrian Somers static struct mbuf *
6185d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
6195d9e6103SBrian Somers               int pri, u_short *proto)
6200053cc58SBrian Somers {
6215d9e6103SBrian Somers   if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED &&
622411675baSBrian Somers       l->ccp.out.state != NULL) {
623411675baSBrian Somers     bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
6245d9e6103SBrian Somers            (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
625411675baSBrian Somers     switch (*proto) {
626411675baSBrian Somers       case PROTO_ICOMPD:
62726af0ae9SBrian Somers         m_settype(bp, MB_ICOMPDOUT);
628411675baSBrian Somers         break;
629411675baSBrian Somers       case PROTO_COMPD:
63026af0ae9SBrian Somers         m_settype(bp, MB_COMPDOUT);
631411675baSBrian Somers         break;
632411675baSBrian Somers     }
633411675baSBrian Somers   }
6345d9e6103SBrian Somers 
6355d9e6103SBrian Somers   return bp;
6360053cc58SBrian Somers }
6370053cc58SBrian Somers 
6385d9e6103SBrian Somers static struct mbuf *
6395d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
6400053cc58SBrian Somers {
641ee6c193fSBrian Somers   /*
642ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
643ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
644ee6c193fSBrian Somers    */
6455d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
646ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
6476815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n",
6486815097bSBrian Somers                  *proto == PROTO_ICOMPD ? "I" : "");
6497308ec68SBrian Somers       /* Decompress incoming data */
6505d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
65198baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
652411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
653411675baSBrian Somers                    MB_CCPOUT);
654411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
655411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
6565d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
657411675baSBrian Somers         switch (*proto) {
658411675baSBrian Somers           case PROTO_ICOMPD:
65926af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
660411675baSBrian Somers             break;
661411675baSBrian Somers           case PROTO_COMPD:
66226af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
663411675baSBrian Somers             break;
664411675baSBrian Somers         }
665411675baSBrian Somers         return bp;
666411675baSBrian Somers       }
66726af0ae9SBrian Somers       m_freem(bp);
668ee6c193fSBrian Somers       bp = NULL;
6696815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
6706815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n");
671ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
6725d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
6735d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
6746815097bSBrian Somers     } else
6756815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n");
6760053cc58SBrian Somers   }
6770053cc58SBrian Somers 
678ee6c193fSBrian Somers   return bp;
6791ae349f5Scvs2svn }
680ed32233cSBrian Somers 
681ed32233cSBrian Somers u_short
682ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
6830053cc58SBrian Somers {
684ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
685ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
6860053cc58SBrian Somers }
6871df0a3b9SBrian Somers 
68806337856SBrian Somers int
6891df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
6901df0a3b9SBrian Somers {
6911df0a3b9SBrian Somers   int f;
6921df0a3b9SBrian Somers 
6931df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
69406337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
6951df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
69606337856SBrian Somers       return 1;
69706337856SBrian Somers     }
6981df0a3b9SBrian Somers 
69906337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
70006337856SBrian Somers 
70106337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
70206337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
70306337856SBrian Somers       return 1;
70406337856SBrian Somers 
70506337856SBrian Somers   return 0;				/* No CCP at all */
7061df0a3b9SBrian Somers }
7075d9e6103SBrian Somers 
7087f89db65SBrian Somers int
7097f89db65SBrian Somers ccp_IsUsable(struct fsm *fp)
7107f89db65SBrian Somers {
7117f89db65SBrian Somers   return 1;
7127f89db65SBrian Somers }
7137f89db65SBrian Somers 
7145d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
715