xref: /freebsd/usr.sbin/ppp/ccp.c (revision 6301d506fb03264736d864d191614a2c5a35efc1)
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);
856cf6ee76SBrian Somers static int 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 {
1536cf6ee76SBrian Somers   struct ccp_opt **o;
154dd0645c5SBrian Somers   struct link *l;
155dd0645c5SBrian Somers   struct ccp *ccp;
1566cf6ee76SBrian Somers   int f;
157dd0645c5SBrian Somers 
1583a2e4f62SBrian Somers   l = command_ChooseLink(arg);
159dd0645c5SBrian Somers   ccp = &l->ccp;
160503a7782SBrian Somers 
161b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1621e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
1635d9e6103SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
164b6217683SBrian Somers     prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
165503a7782SBrian Somers                   protoname(ccp->my_proto), protoname(ccp->his_proto));
166b6217683SBrian Somers     prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
167503a7782SBrian Somers                   ccp->uncompout, ccp->compout,
168503a7782SBrian Somers                   ccp->compin, ccp->uncompin);
1695d9e6103SBrian Somers   }
170cd9647a1SBrian Somers 
1716cf6ee76SBrian Somers   if (ccp->in.algorithm != -1)
1726cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "\n Input Options:  %s\n",
1736cf6ee76SBrian Somers                   (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt));
1746cf6ee76SBrian Somers 
1756cf6ee76SBrian Somers   if (ccp->out.algorithm != -1) {
1766cf6ee76SBrian Somers     o = &ccp->out.opt;
1776cf6ee76SBrian Somers     for (f = 0; f < ccp->out.algorithm; f++)
1786cf6ee76SBrian Somers       if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
1796cf6ee76SBrian Somers         o = &(*o)->next;
1806cf6ee76SBrian Somers     prompt_Printf(arg->prompt, " Output Options: %s\n",
1816cf6ee76SBrian Somers                   (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val));
1826cf6ee76SBrian Somers   }
1836cf6ee76SBrian Somers 
184b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
185479508cfSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
186479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
187479508cfSBrian Somers                 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
188479508cfSBrian Somers                 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
189b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
190b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
191b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1926cf6ee76SBrian Somers #ifdef HAVE_DES
1936cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "           MPPE: ");
1946cf6ee76SBrian Somers   if (ccp->cfg.mppe.keybits)
1956cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits);
1966cf6ee76SBrian Somers   else
1976cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "any bits, ");
1986cf6ee76SBrian Somers   switch (ccp->cfg.mppe.state) {
1996cf6ee76SBrian Somers   case MPPE_STATEFUL:
2006cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "statefull");
2016cf6ee76SBrian Somers     break;
2026cf6ee76SBrian Somers   case MPPE_STATELESS:
2036cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "stateless");
2046cf6ee76SBrian Somers     break;
2056cf6ee76SBrian Somers   case MPPE_ANYSTATE:
2066cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "any state");
2076cf6ee76SBrian Somers     break;
2086cf6ee76SBrian Somers   }
2096cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "%s\n",
2106cf6ee76SBrian Somers                 ccp->cfg.mppe.required ? ", required" : "");
2116cf6ee76SBrian Somers #endif
2126cf6ee76SBrian Somers 
2136cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "\n           DEFLATE:    %s\n",
2141342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
2151342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
2161342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
2171342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
2181342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
219a8d604abSBrian Somers #ifdef HAVE_DES
2206cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "           MPPE:       %s\n",
221a8d604abSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
222a8d604abSBrian Somers #endif
223274e766cSBrian Somers   return 0;
224af57ed9fSAtsushi Murai }
225af57ed9fSAtsushi Murai 
2261ae349f5Scvs2svn void
2276f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
228af57ed9fSAtsushi Murai {
2296f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
2306f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
2316f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
2326f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
233ea661041SBrian Somers }
234ea661041SBrian Somers 
235ea661041SBrian Somers void
2366d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
2376d666775SBrian Somers          const struct fsm_parent *parent)
238ea661041SBrian Somers {
2397308ec68SBrian Somers   /* Initialise ourselves */
2403b0f8d2eSBrian Somers 
241479508cfSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
2426f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
243cd9647a1SBrian Somers 
24403036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
24503036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
246479508cfSBrian Somers   ccp->cfg.fsm.timeout = DEF_FSMRETRY;
247479508cfSBrian Somers   ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
248479508cfSBrian Somers   ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
2491342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
2501342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
2511342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
252a8d604abSBrian Somers #ifdef HAVE_DES
2536cf6ee76SBrian Somers   ccp->cfg.mppe.keybits = 0;
2546cf6ee76SBrian Somers   ccp->cfg.mppe.state = MPPE_ANYSTATE;
2556cf6ee76SBrian Somers   ccp->cfg.mppe.required = 0;
256385167a6SBrian Somers   ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
257a8d604abSBrian Somers #endif
258cd9647a1SBrian Somers 
259503a7782SBrian Somers   ccp_Setup(ccp);
260503a7782SBrian Somers }
261503a7782SBrian Somers 
262503a7782SBrian Somers void
263503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
264503a7782SBrian Somers {
265503a7782SBrian Somers   /* Set ourselves up for a startup */
266503a7782SBrian Somers   ccp->fsm.open_mode = 0;
267503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
268503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
26903036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
27003036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
27103036ec7SBrian Somers   ccp->in.opt.id = -1;
27203036ec7SBrian Somers   ccp->out.opt = NULL;
273503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
274503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
275503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
276af57ed9fSAtsushi Murai }
277af57ed9fSAtsushi Murai 
2786cf6ee76SBrian Somers /*
2796cf6ee76SBrian Somers  * Is ccp *REQUIRED* ?
2806cf6ee76SBrian Somers  * We ask each of the configured ccp protocols if they're required and
2816cf6ee76SBrian Somers  * return TRUE if they are.
2826cf6ee76SBrian Somers  *
2836cf6ee76SBrian Somers  * It's not possible for the peer to reject a required ccp protocol
2846cf6ee76SBrian Somers  * without our state machine bringing the supporting lcp layer down.
2856cf6ee76SBrian Somers  *
2866cf6ee76SBrian Somers  * If ccp is required but not open, the NCP layer should not push
2876cf6ee76SBrian Somers  * any data into the link.
2886cf6ee76SBrian Somers  */
2896cf6ee76SBrian Somers int
2906cf6ee76SBrian Somers ccp_Required(struct ccp *ccp)
2916cf6ee76SBrian Somers {
2926cf6ee76SBrian Somers   int f;
2936cf6ee76SBrian Somers 
2946cf6ee76SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
2956cf6ee76SBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2966cf6ee76SBrian Somers         (*algorithm[f]->Required)(&ccp->fsm))
2976cf6ee76SBrian Somers       return 1;
2986cf6ee76SBrian Somers 
2996cf6ee76SBrian Somers   return 0;
3006cf6ee76SBrian Somers }
3016cf6ee76SBrian Somers 
3026301d506SBrian Somers /*
3036301d506SBrian Somers  * Report whether it's possible to increase a packet's size after
3046301d506SBrian Somers  * compression (and by how much).
3056301d506SBrian Somers  */
3066301d506SBrian Somers int
3076301d506SBrian Somers ccp_MTUOverhead(struct ccp *ccp)
3086301d506SBrian Somers {
3096301d506SBrian Somers   if (ccp->fsm.state == ST_OPENED)
3106301d506SBrian Somers     return algorithm[ccp->out.algorithm]->o.MTUOverhead;
3116301d506SBrian Somers 
3126301d506SBrian Somers   return 0;
3136301d506SBrian Somers }
3146301d506SBrian Somers 
315af57ed9fSAtsushi Murai static void
316479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what)
317af57ed9fSAtsushi Murai {
3187308ec68SBrian Somers   /* Set fsm timer load */
319cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
320cd9647a1SBrian Somers 
321479508cfSBrian Somers   fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
322479508cfSBrian Somers   switch (what) {
323479508cfSBrian Somers     case FSM_REQ_TIMER:
324479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxreq;
325479508cfSBrian Somers       break;
326479508cfSBrian Somers     case FSM_TRM_TIMER:
327479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxtrm;
328479508cfSBrian Somers       break;
329479508cfSBrian Somers     default:
330479508cfSBrian Somers       fp->restart = 1;
331479508cfSBrian Somers       break;
332479508cfSBrian Somers   }
333af57ed9fSAtsushi Murai }
334af57ed9fSAtsushi Murai 
335af57ed9fSAtsushi Murai static void
336944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
337af57ed9fSAtsushi Murai {
3387308ec68SBrian Somers   /* Send config REQ please */
339aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
34003036ec7SBrian Somers   struct ccp_opt **o;
34130c2f2ffSBrian Somers   u_char *cp, buff[100];
34203036ec7SBrian Somers   int f, alloc;
343af57ed9fSAtsushi Murai 
34430c2f2ffSBrian Somers   cp = buff;
34503036ec7SBrian Somers   o = &ccp->out.opt;
34603036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
34783d1af55SBrian Somers   ccp->my_proto = -1;
34803036ec7SBrian Somers   ccp->out.algorithm = -1;
3490053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
3501342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
3517f89db65SBrian Somers         !REJECTED(ccp, algorithm[f]->id) &&
3527f89db65SBrian Somers         (*algorithm[f]->Usable)(fp)) {
3530053cc58SBrian Somers 
354ba081e43SBrian Somers       if (!alloc)
355ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
356ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
357ba081e43SBrian Somers             break;
358ba081e43SBrian Somers 
359ba081e43SBrian Somers       if (alloc || *o == NULL) {
36003036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
36103036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
36203036ec7SBrian Somers         (*o)->val.len = 2;
36303036ec7SBrian Somers         (*o)->next = NULL;
36403036ec7SBrian Somers         (*o)->algorithm = f;
36503036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
366af57ed9fSAtsushi Murai       }
3671ae349f5Scvs2svn 
36803036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
369dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
37030c2f2ffSBrian Somers         break;
37130c2f2ffSBrian Somers       }
3722267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
3732267893fSBrian Somers       cp += (*o)->val.len;
37403036ec7SBrian Somers 
37503036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
37603036ec7SBrian Somers       ccp->out.algorithm = f;
37703036ec7SBrian Somers 
37803036ec7SBrian Somers       if (alloc)
37903036ec7SBrian Somers         o = &(*o)->next;
3801ae349f5Scvs2svn     }
3812267893fSBrian Somers 
382411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
383af57ed9fSAtsushi Murai }
384af57ed9fSAtsushi Murai 
385af57ed9fSAtsushi Murai void
386dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
387af57ed9fSAtsushi Murai {
3887308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
389aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3902267893fSBrian Somers 
39183d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
39283d1af55SBrian Somers   ccp->last_reset = -1;
393411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
394af57ed9fSAtsushi Murai }
395af57ed9fSAtsushi Murai 
396af57ed9fSAtsushi Murai static void
3972267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
398af57ed9fSAtsushi Murai {
3997308ec68SBrian Somers   /* Term REQ just sent by FSM */
400af57ed9fSAtsushi Murai }
401af57ed9fSAtsushi Murai 
402af57ed9fSAtsushi Murai static void
4032267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
404af57ed9fSAtsushi Murai {
4057308ec68SBrian Somers   /* Send Term ACK please */
406411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
407af57ed9fSAtsushi Murai }
408af57ed9fSAtsushi Murai 
4096cf6ee76SBrian Somers static int
410944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
411af57ed9fSAtsushi Murai {
4127308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
413aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
4146cf6ee76SBrian Somers   if (ccp->out.state == NULL)
4156cf6ee76SBrian Somers     return 1;
4166cf6ee76SBrian Somers   return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
417af57ed9fSAtsushi Murai }
418af57ed9fSAtsushi Murai 
419af57ed9fSAtsushi Murai static void
420944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
421af57ed9fSAtsushi Murai {
4227308ec68SBrian Somers   /* We're about to start up ! */
423479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
424479508cfSBrian Somers 
4253a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
426479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
427af57ed9fSAtsushi Murai }
428af57ed9fSAtsushi Murai 
429af57ed9fSAtsushi Murai static void
430897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
431af57ed9fSAtsushi Murai {
432897f9429SBrian Somers   /* About to come down */
433aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
434ba081e43SBrian Somers   struct ccp_opt *next;
435ba081e43SBrian Somers 
4363a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
43703036ec7SBrian Somers   if (ccp->in.state != NULL) {
43803036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
43903036ec7SBrian Somers     ccp->in.state = NULL;
4408d9b9867SBrian Somers     ccp->in.algorithm = -1;
4417308ec68SBrian Somers   }
44203036ec7SBrian Somers   if (ccp->out.state != NULL) {
44303036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
44403036ec7SBrian Somers     ccp->out.state = NULL;
4458d9b9867SBrian Somers     ccp->out.algorithm = -1;
4467308ec68SBrian Somers   }
4478d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
448ba081e43SBrian Somers 
449ba081e43SBrian Somers   while (ccp->out.opt) {
450ba081e43SBrian Somers     next = ccp->out.opt->next;
451ba081e43SBrian Somers     free(ccp->out.opt);
452ba081e43SBrian Somers     ccp->out.opt = next;
453ba081e43SBrian Somers   }
454897f9429SBrian Somers   ccp_Setup(ccp);
455af57ed9fSAtsushi Murai }
456af57ed9fSAtsushi Murai 
457af57ed9fSAtsushi Murai static void
458897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
459af57ed9fSAtsushi Murai {
460897f9429SBrian Somers   /* We're now down */
461e1e8b15eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
462e1e8b15eSBrian Somers   struct ccp_opt *next;
463e1e8b15eSBrian Somers 
4643a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
465e1e8b15eSBrian Somers 
466e1e8b15eSBrian Somers   /*
467e1e8b15eSBrian Somers    * Nuke options that may be left over from sending a REQ but never
468e1e8b15eSBrian Somers    * coming up.
469e1e8b15eSBrian Somers    */
470e1e8b15eSBrian Somers   while (ccp->out.opt) {
471e1e8b15eSBrian Somers     next = ccp->out.opt->next;
472e1e8b15eSBrian Somers     free(ccp->out.opt);
473e1e8b15eSBrian Somers     ccp->out.opt = next;
474e1e8b15eSBrian Somers   }
4756cf6ee76SBrian Somers 
4766cf6ee76SBrian Somers   if (ccp_Required(ccp)) {
4776cf6ee76SBrian Somers     if (fp->link->lcp.fsm.state == ST_OPENED)
4786cf6ee76SBrian Somers       log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
4796cf6ee76SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
4806cf6ee76SBrian Somers   }
481af57ed9fSAtsushi Murai }
482af57ed9fSAtsushi Murai 
4833377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
4846f384573SBrian Somers static int
485944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
486af57ed9fSAtsushi Murai {
4877308ec68SBrian Somers   /* We're now up */
488aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
489e1e8b15eSBrian Somers   struct ccp_opt **o;
4906301d506SBrian Somers   int f, fail;
4916301d506SBrian Somers 
4926301d506SBrian Somers   for (f = fail = 0; f < NALGORITHMS; f++)
4936301d506SBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
4946301d506SBrian Somers         (*algorithm[f]->Required)(&ccp->fsm) &&
4956301d506SBrian Somers         (ccp->in.algorithm != f || ccp->out.algorithm != f)) {
4966301d506SBrian Somers       /* Blow it all away - we haven't negotiated a required algorithm */
4976301d506SBrian Somers       log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
4986301d506SBrian Somers                  fp->link->name, protoname(algorithm[f]->id));
4996301d506SBrian Somers       fail = 1;
5006301d506SBrian Somers     }
5016301d506SBrian Somers 
5026301d506SBrian Somers   if (fail) {
5036301d506SBrian Somers     ccp->his_proto = ccp->my_proto = -1;
5046301d506SBrian Somers     fsm_Close(fp);
5056301d506SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
5066301d506SBrian Somers     return 0;
5076301d506SBrian Somers   }
508479508cfSBrian Somers 
5093a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
510479508cfSBrian Somers 
51103036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
51203036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
51303036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
51403036ec7SBrian Somers     if (ccp->in.state == NULL) {
515dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
516d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
51783d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
518dd7e2610SBrian Somers       fsm_Close(fp);
519479508cfSBrian Somers       return 0;
52079d1bdaeSBrian Somers     }
521af57ed9fSAtsushi Murai   }
522af57ed9fSAtsushi Murai 
523e1e8b15eSBrian Somers   o = &ccp->out.opt;
524e1e8b15eSBrian Somers   for (f = 0; f < ccp->out.algorithm; f++)
525e1e8b15eSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
526e1e8b15eSBrian Somers       o = &(*o)->next;
527e1e8b15eSBrian Somers 
52803036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
52903036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
530e1e8b15eSBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)(&(*o)->val);
53103036ec7SBrian Somers     if (ccp->out.state == NULL) {
532dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
533d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
53483d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
535dd7e2610SBrian Somers       fsm_Close(fp);
536479508cfSBrian Somers       return 0;
537247ab36dSBrian Somers     }
538af57ed9fSAtsushi Murai   }
539af57ed9fSAtsushi Murai 
540479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
541479508cfSBrian Somers 
542dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
543d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
54483d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
545479508cfSBrian Somers 
5466f384573SBrian Somers   return 1;
547af57ed9fSAtsushi Murai }
548af57ed9fSAtsushi Murai 
549af57ed9fSAtsushi Murai static void
55030c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
55130c2f2ffSBrian Somers                 struct fsm_decode *dec)
552af57ed9fSAtsushi Murai {
5537308ec68SBrian Somers   /* Deal with incoming data */
554aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
55531516407SBrian Somers   int type, length, f;
55603036ec7SBrian Somers   const char *end;
557af57ed9fSAtsushi Murai 
55831516407SBrian Somers   if (mode_type == MODE_REQ)
55931516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
56031516407SBrian Somers 
561af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
562af57ed9fSAtsushi Murai     type = *cp;
563af57ed9fSAtsushi Murai     length = cp[1];
56403036ec7SBrian Somers 
565d47dceb8SBrian Somers     if (length == 0) {
566dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
567d47dceb8SBrian Somers       break;
568d47dceb8SBrian Somers     }
569d47dceb8SBrian Somers 
57003036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
57103036ec7SBrian Somers       length = sizeof(struct lcp_opt);
572dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
573d47dceb8SBrian Somers                 fp->link->name, length);
57403036ec7SBrian Somers     }
575af57ed9fSAtsushi Murai 
5760053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
5770053cc58SBrian Somers       if (algorithm[f]->id == type)
5780053cc58SBrian Somers         break;
579af57ed9fSAtsushi Murai 
58003036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
58103036ec7SBrian Somers     if (end == NULL)
58203036ec7SBrian Somers       end = "";
58303036ec7SBrian Somers 
584d6d3eeabSBrian Somers     log_Printf(LogCCP, " %s[%d] %s\n", protoname(type), length, end);
58503036ec7SBrian Somers 
5860053cc58SBrian Somers     if (f == -1) {
5870053cc58SBrian Somers       /* Don't understand that :-( */
5880053cc58SBrian Somers       if (mode_type == MODE_REQ) {
58983d1af55SBrian Somers         ccp->my_reject |= (1 << type);
59030c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
59130c2f2ffSBrian Somers         dec->rejend += length;
5920053cc58SBrian Somers       }
5930053cc58SBrian Somers     } else {
59403036ec7SBrian Somers       struct ccp_opt *o;
5950053cc58SBrian Somers 
5969780ef31SBrian Somers       switch (mode_type) {
597af57ed9fSAtsushi Murai       case MODE_REQ:
5981342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
5997f89db65SBrian Somers             (*algorithm[f]->Usable)(fp) &&
6001342caedSBrian Somers             ccp->in.algorithm == -1) {
60103036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
60203036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
6030053cc58SBrian Somers           case MODE_REJ:
60403036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
60503036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
6060053cc58SBrian Somers             break;
6070053cc58SBrian Somers           case MODE_NAK:
60803036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
60903036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
6100053cc58SBrian Somers             break;
6110053cc58SBrian Somers           case MODE_ACK:
61230c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
61330c2f2ffSBrian Somers 	    dec->ackend += length;
61483d1af55SBrian Somers 	    ccp->his_proto = type;
61503036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
6160053cc58SBrian Somers             break;
6170053cc58SBrian Somers           }
618af57ed9fSAtsushi Murai 	} else {
61930c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
62030c2f2ffSBrian Somers 	  dec->rejend += length;
621af57ed9fSAtsushi Murai 	}
622af57ed9fSAtsushi Murai 	break;
623af57ed9fSAtsushi Murai       case MODE_NAK:
62403036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
62503036ec7SBrian Somers           if (o->val.id == cp[0])
62603036ec7SBrian Somers             break;
62703036ec7SBrian Somers         if (o == NULL)
6289b996792SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
6299b996792SBrian Somers                      " option\n", fp->link->name);
6300053cc58SBrian Somers         else {
63103036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
6326cf6ee76SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val, &ccp->cfg) == MODE_ACK)
63383d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
6341ae349f5Scvs2svn           else {
63583d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
63683d1af55SBrian Somers 	    ccp->my_proto = -1;
6376cf6ee76SBrian Somers             if (algorithm[f]->Required(fp)) {
6386cf6ee76SBrian Somers               log_Printf(LogWARN, "%s: Cannot understand peers (required)"
6396cf6ee76SBrian Somers                          " %s negotiation\n", fp->link->name,
6406cf6ee76SBrian Somers                          protoname(algorithm[f]->id));
6416cf6ee76SBrian Somers               fsm_Close(&fp->link->lcp.fsm);
6426cf6ee76SBrian Somers             }
6431ae349f5Scvs2svn           }
6440053cc58SBrian Somers         }
6450053cc58SBrian Somers         break;
646af57ed9fSAtsushi Murai       case MODE_REJ:
64783d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
64883d1af55SBrian Somers 	ccp->my_proto = -1;
6496cf6ee76SBrian Somers         if (algorithm[f]->Required(fp)) {
6506cf6ee76SBrian Somers           log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
6516cf6ee76SBrian Somers                      fp->link->name, protoname(algorithm[f]->id));
6526cf6ee76SBrian Somers           fsm_Close(&fp->link->lcp.fsm);
6536cf6ee76SBrian Somers         }
654af57ed9fSAtsushi Murai 	break;
655af57ed9fSAtsushi Murai       }
656af57ed9fSAtsushi Murai     }
6570053cc58SBrian Somers 
65803036ec7SBrian Somers     plen -= cp[1];
65903036ec7SBrian Somers     cp += cp[1];
660af57ed9fSAtsushi Murai   }
6610053cc58SBrian Somers 
662e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
6631342caedSBrian Somers     if (dec->rejend != dec->rej) {
66403036ec7SBrian Somers       /* rejects are preferred */
66503036ec7SBrian Somers       dec->ackend = dec->ack;
66603036ec7SBrian Somers       dec->nakend = dec->nak;
66703036ec7SBrian Somers       if (ccp->in.state == NULL) {
66883d1af55SBrian Somers         ccp->his_proto = -1;
66903036ec7SBrian Somers         ccp->in.algorithm = -1;
67003036ec7SBrian Somers       }
6711342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
67203036ec7SBrian Somers       /* then NAKs */
67303036ec7SBrian Somers       dec->ackend = dec->ack;
67403036ec7SBrian Somers       if (ccp->in.state == NULL) {
67503036ec7SBrian Somers         ccp->his_proto = -1;
67603036ec7SBrian Somers         ccp->in.algorithm = -1;
677247ab36dSBrian Somers       }
6781ae349f5Scvs2svn     }
6790053cc58SBrian Somers   }
680af57ed9fSAtsushi Murai }
681af57ed9fSAtsushi Murai 
6825d9e6103SBrian Somers extern struct mbuf *
6835d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
684af57ed9fSAtsushi Murai {
6857308ec68SBrian Somers   /* Got PROTO_CCP from link */
68626af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
687455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
6885d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
689af57ed9fSAtsushi Murai   else {
690641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
691dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
6925d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
69326af0ae9SBrian Somers     m_freem(bp);
694af57ed9fSAtsushi Murai   }
6955d9e6103SBrian Somers   return NULL;
696af57ed9fSAtsushi Murai }
6970053cc58SBrian Somers 
698503a7782SBrian Somers static void
699503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
7000053cc58SBrian Somers {
7017308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
702f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
703f4768038SBrian Somers 
704f4768038SBrian Somers   if (ccp->reset_sent != -1) {
705f4768038SBrian Somers     if (id != ccp->reset_sent) {
706a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
707d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
70898baf7c8SBrian Somers       return;
70998baf7c8SBrian Somers     }
71098baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
711f4768038SBrian Somers   } else if (id == ccp->last_reset)
712dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
713d47dceb8SBrian Somers                fp->link->name);
71498baf7c8SBrian Somers   else {
715a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
716d47dceb8SBrian Somers                fp->link->name, id);
71798baf7c8SBrian Somers     return;
71898baf7c8SBrian Somers   }
71998baf7c8SBrian Somers 
720f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
721f4768038SBrian Somers   ccp->reset_sent = -1;
72203036ec7SBrian Somers   if (ccp->in.state != NULL)
72303036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
7240053cc58SBrian Somers }
7250053cc58SBrian Somers 
7265d9e6103SBrian Somers static struct mbuf *
7275d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
7285d9e6103SBrian Somers               int pri, u_short *proto)
7290053cc58SBrian Somers {
7306cf6ee76SBrian Somers   if (PROTO_COMPRESSIBLE(*proto)) {
7316cf6ee76SBrian Somers     if (l->ccp.fsm.state != ST_OPENED) {
7326cf6ee76SBrian Somers       if (ccp_Required(&l->ccp)) {
7336cf6ee76SBrian Somers         /* The NCP layer shouldn't have let this happen ! */
7346cf6ee76SBrian Somers         log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
7356cf6ee76SBrian Somers                    " required CCP layer\n", l->name);
7366cf6ee76SBrian Somers         m_freem(bp);
7376cf6ee76SBrian Somers         bp = NULL;
7386cf6ee76SBrian Somers       }
7396cf6ee76SBrian Somers     } else if (l->ccp.out.state != NULL) {
740411675baSBrian Somers       bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
7415d9e6103SBrian Somers              (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
742411675baSBrian Somers       switch (*proto) {
743411675baSBrian Somers         case PROTO_ICOMPD:
74426af0ae9SBrian Somers           m_settype(bp, MB_ICOMPDOUT);
745411675baSBrian Somers           break;
746411675baSBrian Somers         case PROTO_COMPD:
74726af0ae9SBrian Somers           m_settype(bp, MB_COMPDOUT);
748411675baSBrian Somers           break;
749411675baSBrian Somers       }
750411675baSBrian Somers     }
7516cf6ee76SBrian Somers   }
7525d9e6103SBrian Somers 
7535d9e6103SBrian Somers   return bp;
7540053cc58SBrian Somers }
7550053cc58SBrian Somers 
7565d9e6103SBrian Somers static struct mbuf *
7575d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
7580053cc58SBrian Somers {
759ee6c193fSBrian Somers   /*
760ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
761ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
762ee6c193fSBrian Somers    */
7635d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
764ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
7656815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n",
7666815097bSBrian Somers                  *proto == PROTO_ICOMPD ? "I" : "");
7677308ec68SBrian Somers       /* Decompress incoming data */
7685d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
76998baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
770411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
771411675baSBrian Somers                    MB_CCPOUT);
772411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
773411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
7745d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
775411675baSBrian Somers         switch (*proto) {
776411675baSBrian Somers           case PROTO_ICOMPD:
77726af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
778411675baSBrian Somers             break;
779411675baSBrian Somers           case PROTO_COMPD:
78026af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
781411675baSBrian Somers             break;
782411675baSBrian Somers         }
783411675baSBrian Somers         return bp;
784411675baSBrian Somers       }
78526af0ae9SBrian Somers       m_freem(bp);
786ee6c193fSBrian Somers       bp = NULL;
7876815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
7886815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n");
789ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
7905d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
7915d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
7926815097bSBrian Somers     } else
7936815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n");
7940053cc58SBrian Somers   }
7950053cc58SBrian Somers 
796ee6c193fSBrian Somers   return bp;
7971ae349f5Scvs2svn }
798ed32233cSBrian Somers 
799ed32233cSBrian Somers u_short
800ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
8010053cc58SBrian Somers {
802ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
803ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
8040053cc58SBrian Somers }
8051df0a3b9SBrian Somers 
80606337856SBrian Somers int
8071df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
8081df0a3b9SBrian Somers {
8091df0a3b9SBrian Somers   int f;
8101df0a3b9SBrian Somers 
8111df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
81206337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
8131df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
81406337856SBrian Somers       return 1;
81506337856SBrian Somers     }
8161df0a3b9SBrian Somers 
81706337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
81806337856SBrian Somers 
81906337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
82006337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
82106337856SBrian Somers       return 1;
82206337856SBrian Somers 
82306337856SBrian Somers   return 0;				/* No CCP at all */
8241df0a3b9SBrian Somers }
8255d9e6103SBrian Somers 
8267f89db65SBrian Somers int
8276cf6ee76SBrian Somers ccp_DefaultUsable(struct fsm *fp)
8287f89db65SBrian Somers {
8297f89db65SBrian Somers   return 1;
8307f89db65SBrian Somers }
8317f89db65SBrian Somers 
8326cf6ee76SBrian Somers int
8336cf6ee76SBrian Somers ccp_DefaultRequired(struct fsm *fp)
8346cf6ee76SBrian Somers {
8356cf6ee76SBrian Somers   return 0;
8366cf6ee76SBrian Somers }
8376cf6ee76SBrian Somers 
8385d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
839