xref: /freebsd/usr.sbin/ppp/ccp.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
165309e5cSBrian Somers /*-
2*1de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*1de7b4b8SPedro F. Giffuni  *
465309e5cSBrian Somers  * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
565309e5cSBrian Somers  *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
665309e5cSBrian Somers  *                           Internet Initiative Japan, Inc (IIJ)
765309e5cSBrian Somers  * All rights reserved.
8af57ed9fSAtsushi Murai  *
965309e5cSBrian Somers  * Redistribution and use in source and binary forms, with or without
1065309e5cSBrian Somers  * modification, are permitted provided that the following conditions
1165309e5cSBrian Somers  * are met:
1265309e5cSBrian Somers  * 1. Redistributions of source code must retain the above copyright
1365309e5cSBrian Somers  *    notice, this list of conditions and the following disclaimer.
1465309e5cSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
1565309e5cSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
1665309e5cSBrian Somers  *    documentation and/or other materials provided with the distribution.
17af57ed9fSAtsushi Murai  *
1865309e5cSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1965309e5cSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2065309e5cSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2165309e5cSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2265309e5cSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2365309e5cSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2465309e5cSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2565309e5cSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2665309e5cSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2765309e5cSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2865309e5cSBrian Somers  * SUCH DAMAGE.
29af57ed9fSAtsushi Murai  *
3097d92980SPeter Wemm  * $FreeBSD$
31af57ed9fSAtsushi Murai  */
3265309e5cSBrian Somers 
33972a1bcfSBrian Somers #include <sys/param.h>
3475240ed1SBrian Somers #include <netinet/in.h>
35eaa4df37SBrian Somers #include <netinet/in_systm.h>
36eaa4df37SBrian Somers #include <netinet/ip.h>
3730949fd4SBrian Somers #include <sys/socket.h>
381fa665f5SBrian Somers #include <sys/un.h>
3975240ed1SBrian Somers 
406eafd353SBrian Somers #include <stdarg.h>
4175240ed1SBrian Somers #include <stdio.h>
4203036ec7SBrian Somers #include <stdlib.h>
43eb6e5e05SBrian Somers #include <string.h>	/* memcpy() on some archs */
4485b542cfSBrian Somers #include <termios.h>
4575240ed1SBrian Somers 
465d9e6103SBrian Somers #include "layer.h"
47c9e11a11SBrian Somers #include "defs.h"
48b6e82f33SBrian Somers #include "command.h"
4975240ed1SBrian Somers #include "mbuf.h"
5075240ed1SBrian Somers #include "log.h"
5175240ed1SBrian Somers #include "timer.h"
52af57ed9fSAtsushi Murai #include "fsm.h"
535d9e6103SBrian Somers #include "proto.h"
54ed6a16c1SPoul-Henning Kamp #include "pred.h"
550053cc58SBrian Somers #include "deflate.h"
565828db6dSBrian Somers #include "throughput.h"
575828db6dSBrian Somers #include "iplist.h"
58eaa4df37SBrian Somers #include "slcompress.h"
595a72b6edSBrian Somers #include "lqr.h"
605a72b6edSBrian Somers #include "hdlc.h"
611038894eSBrian Somers #include "lcp.h"
621038894eSBrian Somers #include "ccp.h"
6330949fd4SBrian Somers #include "ncpaddr.h"
645828db6dSBrian Somers #include "ipcp.h"
655ca5389aSBrian Somers #include "filter.h"
6685b542cfSBrian Somers #include "descriptor.h"
6785b542cfSBrian Somers #include "prompt.h"
68503a7782SBrian Somers #include "link.h"
693b0f8d2eSBrian Somers #include "mp.h"
70ed32233cSBrian Somers #include "async.h"
71ed32233cSBrian Somers #include "physical.h"
72972a1bcfSBrian Somers #ifndef NORADIUS
73972a1bcfSBrian Somers #include "radius.h"
74972a1bcfSBrian Somers #endif
75fb11a9c2SBrian Somers #ifndef NODES
76a8d604abSBrian Somers #include "mppe.h"
77a8d604abSBrian Somers #endif
7830949fd4SBrian Somers #include "ipv6cp.h"
7930949fd4SBrian Somers #include "ncp.h"
803b0f8d2eSBrian Somers #include "bundle.h"
81af57ed9fSAtsushi Murai 
82927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
832267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
842267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
85ff360cc9SBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
8630c2f2ffSBrian Somers                             struct fsm_decode *);
87927145beSBrian Somers static void CcpLayerStart(struct fsm *);
88927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
896f384573SBrian Somers static int CcpLayerUp(struct fsm *);
90927145beSBrian Somers static void CcpLayerDown(struct fsm *);
91479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int);
926cf6ee76SBrian Somers static int CcpRecvResetReq(struct fsm *);
93503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
94af57ed9fSAtsushi Murai 
9583d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
96af57ed9fSAtsushi Murai   CcpLayerUp,
97af57ed9fSAtsushi Murai   CcpLayerDown,
98af57ed9fSAtsushi Murai   CcpLayerStart,
99af57ed9fSAtsushi Murai   CcpLayerFinish,
100af57ed9fSAtsushi Murai   CcpInitRestartCounter,
101af57ed9fSAtsushi Murai   CcpSendConfigReq,
1022267893fSBrian Somers   CcpSentTerminateReq,
103af57ed9fSAtsushi Murai   CcpSendTerminateAck,
104af57ed9fSAtsushi Murai   CcpDecodeConfig,
105503a7782SBrian Somers   CcpRecvResetReq,
106503a7782SBrian Somers   CcpRecvResetAck
107af57ed9fSAtsushi Murai };
108af57ed9fSAtsushi Murai 
109182c898aSBrian Somers static const char * const ccp_TimerNames[] =
1106f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
1116f384573SBrian Somers 
112d6d3eeabSBrian Somers static const char *
113d6d3eeabSBrian Somers protoname(int proto)
114d6d3eeabSBrian Somers {
115182c898aSBrian Somers   static char const * const cftypes[] = {
116d6d3eeabSBrian Somers     /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
1179e836af5SBrian Somers     "OUI",		/* 0: OUI */
1189e836af5SBrian Somers     "PRED1",		/* 1: Predictor type 1 */
1199e836af5SBrian Somers     "PRED2",		/* 2: Predictor type 2 */
1209e836af5SBrian Somers     "PUDDLE",		/* 3: Puddle Jumber */
121d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
122d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
1239e836af5SBrian Somers     "HWPPC",		/* 16: Hewlett-Packard PPC */
1244bc84b8cSBrian Somers     "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
125a8d604abSBrian Somers     "MPPE",		/* 18: Microsoft PPC (rfc2118) and */
126a8d604abSBrian Somers 			/*     Microsoft PPE (draft-ietf-pppext-mppe) */
1274bc84b8cSBrian Somers     "GAND",		/* 19: Gandalf FZA (rfc1993) */
128b6e82f33SBrian Somers     "V42BIS",		/* 20: ARG->DATA.42bis compression */
1290053cc58SBrian Somers     "BSD",		/* 21: BSD LZW Compress */
130d6d3eeabSBrian Somers     NULL,
1314bc84b8cSBrian Somers     "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1324bc84b8cSBrian Somers     "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
1331342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1344bc84b8cSBrian Somers     "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1354bc84b8cSBrian Somers     "DEFLATE",		/* 26: Deflate (rfc1979) */
136af57ed9fSAtsushi Murai   };
137af57ed9fSAtsushi Murai 
138057f1760SBrian Somers   if (proto < 0 || (unsigned)proto > sizeof cftypes / sizeof *cftypes ||
1399ea69707SBrian Somers       cftypes[proto] == NULL) {
1409ea69707SBrian Somers     if (proto == -1)
1419ea69707SBrian Somers       return "none";
142d6d3eeabSBrian Somers     return HexStr(proto, NULL, 0);
1439ea69707SBrian Somers   }
1449e836af5SBrian Somers 
1450053cc58SBrian Somers   return cftypes[proto];
1460053cc58SBrian Somers }
1470053cc58SBrian Somers 
1484bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
149182c898aSBrian Somers static const struct ccp_algorithm * const algorithm[] = {
1504bc84b8cSBrian Somers   &DeflateAlgorithm,
1510053cc58SBrian Somers   &Pred1Algorithm,
1524bc84b8cSBrian Somers   &PppdDeflateAlgorithm
153fb11a9c2SBrian Somers #ifndef NODES
154a8d604abSBrian Somers   , &MPPEAlgorithm
155a8d604abSBrian Somers #endif
1560053cc58SBrian Somers };
1570053cc58SBrian Somers 
15870ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1590053cc58SBrian Somers 
160274e766cSBrian Somers int
161503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
162af57ed9fSAtsushi Murai {
1636cf6ee76SBrian Somers   struct ccp_opt **o;
164dd0645c5SBrian Somers   struct link *l;
165dd0645c5SBrian Somers   struct ccp *ccp;
1666cf6ee76SBrian Somers   int f;
167dd0645c5SBrian Somers 
1683a2e4f62SBrian Somers   l = command_ChooseLink(arg);
169dd0645c5SBrian Somers   ccp = &l->ccp;
170503a7782SBrian Somers 
171b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1721e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
1735d9e6103SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
174b6217683SBrian Somers     prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
175503a7782SBrian Somers                   protoname(ccp->my_proto), protoname(ccp->his_proto));
176b6217683SBrian Somers     prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
177503a7782SBrian Somers                   ccp->uncompout, ccp->compout,
178503a7782SBrian Somers                   ccp->compin, ccp->uncompin);
1795d9e6103SBrian Somers   }
180cd9647a1SBrian Somers 
1816cf6ee76SBrian Somers   if (ccp->in.algorithm != -1)
1826cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "\n Input Options:  %s\n",
1836cf6ee76SBrian Somers                   (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt));
1846cf6ee76SBrian Somers 
1856cf6ee76SBrian Somers   if (ccp->out.algorithm != -1) {
1866cf6ee76SBrian Somers     o = &ccp->out.opt;
1876cf6ee76SBrian Somers     for (f = 0; f < ccp->out.algorithm; f++)
1886cf6ee76SBrian Somers       if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
1896cf6ee76SBrian Somers         o = &(*o)->next;
1906cf6ee76SBrian Somers     prompt_Printf(arg->prompt, " Output Options: %s\n",
1916cf6ee76SBrian Somers                   (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val));
1926cf6ee76SBrian Somers   }
1936cf6ee76SBrian Somers 
194b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
195479508cfSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
196479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
197479508cfSBrian Somers                 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
198479508cfSBrian Somers                 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
199b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
200b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
201b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
202fb11a9c2SBrian Somers #ifndef NODES
2036cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "           MPPE: ");
2046cf6ee76SBrian Somers   if (ccp->cfg.mppe.keybits)
2056cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits);
2066cf6ee76SBrian Somers   else
2076cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "any bits, ");
2086cf6ee76SBrian Somers   switch (ccp->cfg.mppe.state) {
2096cf6ee76SBrian Somers   case MPPE_STATEFUL:
21080a18377SBrian Somers     prompt_Printf(arg->prompt, "stateful");
2116cf6ee76SBrian Somers     break;
2126cf6ee76SBrian Somers   case MPPE_STATELESS:
2136cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "stateless");
2146cf6ee76SBrian Somers     break;
2156cf6ee76SBrian Somers   case MPPE_ANYSTATE:
2166cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "any state");
2176cf6ee76SBrian Somers     break;
2186cf6ee76SBrian Somers   }
2196cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "%s\n",
2206cf6ee76SBrian Somers                 ccp->cfg.mppe.required ? ", required" : "");
2216cf6ee76SBrian Somers #endif
2226cf6ee76SBrian Somers 
2236cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "\n           DEFLATE:    %s\n",
2241342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
2251342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
2261342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
2271342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
2281342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
229fb11a9c2SBrian Somers #ifndef NODES
2306cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "           MPPE:       %s\n",
231a8d604abSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
232a8d604abSBrian Somers #endif
233274e766cSBrian Somers   return 0;
234af57ed9fSAtsushi Murai }
235af57ed9fSAtsushi Murai 
2361ae349f5Scvs2svn void
2376f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
238af57ed9fSAtsushi Murai {
2396f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
2406f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
2416f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
2426f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
243ea661041SBrian Somers }
244ea661041SBrian Somers 
245ea661041SBrian Somers void
2466d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
2476d666775SBrian Somers          const struct fsm_parent *parent)
248ea661041SBrian Somers {
2497308ec68SBrian Somers   /* Initialise ourselves */
2503b0f8d2eSBrian Somers 
251479508cfSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
2526f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
253cd9647a1SBrian Somers 
25403036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
25503036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
256479508cfSBrian Somers   ccp->cfg.fsm.timeout = DEF_FSMRETRY;
257479508cfSBrian Somers   ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
258479508cfSBrian Somers   ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
2591342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
2601342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
2611342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
262fb11a9c2SBrian Somers #ifndef NODES
2636cf6ee76SBrian Somers   ccp->cfg.mppe.keybits = 0;
2646cf6ee76SBrian Somers   ccp->cfg.mppe.state = MPPE_ANYSTATE;
2656cf6ee76SBrian Somers   ccp->cfg.mppe.required = 0;
266385167a6SBrian Somers   ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
267a8d604abSBrian Somers #endif
268cd9647a1SBrian Somers 
269503a7782SBrian Somers   ccp_Setup(ccp);
270503a7782SBrian Somers }
271503a7782SBrian Somers 
272503a7782SBrian Somers void
273503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
274503a7782SBrian Somers {
275503a7782SBrian Somers   /* Set ourselves up for a startup */
276503a7782SBrian Somers   ccp->fsm.open_mode = 0;
277503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
278503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
27903036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
28003036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
281ff360cc9SBrian Somers   ccp->in.opt.hdr.id = -1;
28203036ec7SBrian Somers   ccp->out.opt = NULL;
283503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
284503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
285503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
286af57ed9fSAtsushi Murai }
287af57ed9fSAtsushi Murai 
2886cf6ee76SBrian Somers /*
2896cf6ee76SBrian Somers  * Is ccp *REQUIRED* ?
2906cf6ee76SBrian Somers  * We ask each of the configured ccp protocols if they're required and
2916cf6ee76SBrian Somers  * return TRUE if they are.
2926cf6ee76SBrian Somers  *
2936cf6ee76SBrian Somers  * It's not possible for the peer to reject a required ccp protocol
2946cf6ee76SBrian Somers  * without our state machine bringing the supporting lcp layer down.
2956cf6ee76SBrian Somers  *
2966cf6ee76SBrian Somers  * If ccp is required but not open, the NCP layer should not push
2976cf6ee76SBrian Somers  * any data into the link.
2986cf6ee76SBrian Somers  */
2996cf6ee76SBrian Somers int
3006cf6ee76SBrian Somers ccp_Required(struct ccp *ccp)
3016cf6ee76SBrian Somers {
302057f1760SBrian Somers   unsigned f;
3036cf6ee76SBrian Somers 
3046cf6ee76SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
3056cf6ee76SBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
3066cf6ee76SBrian Somers         (*algorithm[f]->Required)(&ccp->fsm))
3076cf6ee76SBrian Somers       return 1;
3086cf6ee76SBrian Somers 
3096cf6ee76SBrian Somers   return 0;
3106cf6ee76SBrian Somers }
3116cf6ee76SBrian Somers 
3126301d506SBrian Somers /*
3136301d506SBrian Somers  * Report whether it's possible to increase a packet's size after
3146301d506SBrian Somers  * compression (and by how much).
3156301d506SBrian Somers  */
3166301d506SBrian Somers int
3176301d506SBrian Somers ccp_MTUOverhead(struct ccp *ccp)
3186301d506SBrian Somers {
3197e62c638SBrian Somers   if (ccp->fsm.state == ST_OPENED && ccp->out.algorithm >= 0)
3206301d506SBrian Somers     return algorithm[ccp->out.algorithm]->o.MTUOverhead;
3216301d506SBrian Somers 
3226301d506SBrian Somers   return 0;
3236301d506SBrian Somers }
3246301d506SBrian Somers 
325af57ed9fSAtsushi Murai static void
326479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what)
327af57ed9fSAtsushi Murai {
3287308ec68SBrian Somers   /* Set fsm timer load */
329cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
330cd9647a1SBrian Somers 
331479508cfSBrian Somers   fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
332479508cfSBrian Somers   switch (what) {
333479508cfSBrian Somers     case FSM_REQ_TIMER:
334479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxreq;
335479508cfSBrian Somers       break;
336479508cfSBrian Somers     case FSM_TRM_TIMER:
337479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxtrm;
338479508cfSBrian Somers       break;
339479508cfSBrian Somers     default:
340479508cfSBrian Somers       fp->restart = 1;
341479508cfSBrian Somers       break;
342479508cfSBrian Somers   }
343af57ed9fSAtsushi Murai }
344af57ed9fSAtsushi Murai 
345af57ed9fSAtsushi Murai static void
346944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
347af57ed9fSAtsushi Murai {
3487308ec68SBrian Somers   /* Send config REQ please */
349aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
35003036ec7SBrian Somers   struct ccp_opt **o;
35130c2f2ffSBrian Somers   u_char *cp, buff[100];
352057f1760SBrian Somers   unsigned f;
353057f1760SBrian Somers   int alloc;
354af57ed9fSAtsushi Murai 
35530c2f2ffSBrian Somers   cp = buff;
35603036ec7SBrian Somers   o = &ccp->out.opt;
35703036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
35883d1af55SBrian Somers   ccp->my_proto = -1;
35903036ec7SBrian Somers   ccp->out.algorithm = -1;
3600053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
3611342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
3627f89db65SBrian Somers         !REJECTED(ccp, algorithm[f]->id) &&
3637f89db65SBrian Somers         (*algorithm[f]->Usable)(fp)) {
3640053cc58SBrian Somers 
365ba081e43SBrian Somers       if (!alloc)
366ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
367057f1760SBrian Somers           if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == (int)f)
368ba081e43SBrian Somers             break;
369ba081e43SBrian Somers 
370ba081e43SBrian Somers       if (alloc || *o == NULL) {
3715d604c11SBrian Somers         if ((*o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt))) == NULL) {
3725d604c11SBrian Somers 	  log_Printf(LogERROR, "%s: Not enough memory for CCP REQ !\n",
3735d604c11SBrian Somers 		     fp->link->name);
3745d604c11SBrian Somers 	  break;
3755d604c11SBrian Somers 	}
376ff360cc9SBrian Somers         (*o)->val.hdr.id = algorithm[f]->id;
377ff360cc9SBrian Somers         (*o)->val.hdr.len = 2;
37803036ec7SBrian Somers         (*o)->next = NULL;
37903036ec7SBrian Somers         (*o)->algorithm = f;
3808fb5ef5aSBrian Somers         (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
381af57ed9fSAtsushi Murai       }
3821ae349f5Scvs2svn 
383ff360cc9SBrian Somers       if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
384dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
38530c2f2ffSBrian Somers         break;
38630c2f2ffSBrian Somers       }
387ff360cc9SBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.hdr.len);
388ff360cc9SBrian Somers       cp += (*o)->val.hdr.len;
38903036ec7SBrian Somers 
390ff360cc9SBrian Somers       ccp->my_proto = (*o)->val.hdr.id;
39103036ec7SBrian Somers       ccp->out.algorithm = f;
39203036ec7SBrian Somers 
39303036ec7SBrian Somers       if (alloc)
39403036ec7SBrian Somers         o = &(*o)->next;
3951ae349f5Scvs2svn     }
3962267893fSBrian Somers 
397411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
398af57ed9fSAtsushi Murai }
399af57ed9fSAtsushi Murai 
400af57ed9fSAtsushi Murai void
401dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
402af57ed9fSAtsushi Murai {
4037308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
404aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
4052267893fSBrian Somers 
40683d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
40783d1af55SBrian Somers   ccp->last_reset = -1;
408411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
409af57ed9fSAtsushi Murai }
410af57ed9fSAtsushi Murai 
411af57ed9fSAtsushi Murai static void
412057f1760SBrian Somers CcpSentTerminateReq(struct fsm *fp __unused)
413af57ed9fSAtsushi Murai {
4147308ec68SBrian Somers   /* Term REQ just sent by FSM */
415af57ed9fSAtsushi Murai }
416af57ed9fSAtsushi Murai 
417af57ed9fSAtsushi Murai static void
4182267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
419af57ed9fSAtsushi Murai {
4207308ec68SBrian Somers   /* Send Term ACK please */
421411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
422af57ed9fSAtsushi Murai }
423af57ed9fSAtsushi Murai 
4246cf6ee76SBrian Somers static int
425944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
426af57ed9fSAtsushi Murai {
4277308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
428aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
4296cf6ee76SBrian Somers   if (ccp->out.state == NULL)
4306cf6ee76SBrian Somers     return 1;
4316cf6ee76SBrian Somers   return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
432af57ed9fSAtsushi Murai }
433af57ed9fSAtsushi Murai 
434af57ed9fSAtsushi Murai static void
435944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
436af57ed9fSAtsushi Murai {
4377308ec68SBrian Somers   /* We're about to start up ! */
438479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
439479508cfSBrian Somers 
4403a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
441479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
442af57ed9fSAtsushi Murai }
443af57ed9fSAtsushi Murai 
444af57ed9fSAtsushi Murai static void
445897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
446af57ed9fSAtsushi Murai {
447897f9429SBrian Somers   /* About to come down */
448aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
449ba081e43SBrian Somers   struct ccp_opt *next;
450ba081e43SBrian Somers 
4513a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
45203036ec7SBrian Somers   if (ccp->in.state != NULL) {
45303036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
45403036ec7SBrian Somers     ccp->in.state = NULL;
4558d9b9867SBrian Somers     ccp->in.algorithm = -1;
4567308ec68SBrian Somers   }
45703036ec7SBrian Somers   if (ccp->out.state != NULL) {
45803036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
45903036ec7SBrian Somers     ccp->out.state = NULL;
4608d9b9867SBrian Somers     ccp->out.algorithm = -1;
4617308ec68SBrian Somers   }
4628d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
463ba081e43SBrian Somers 
464ba081e43SBrian Somers   while (ccp->out.opt) {
465ba081e43SBrian Somers     next = ccp->out.opt->next;
466ba081e43SBrian Somers     free(ccp->out.opt);
467ba081e43SBrian Somers     ccp->out.opt = next;
468ba081e43SBrian Somers   }
469897f9429SBrian Somers   ccp_Setup(ccp);
470af57ed9fSAtsushi Murai }
471af57ed9fSAtsushi Murai 
472af57ed9fSAtsushi Murai static void
473897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
474af57ed9fSAtsushi Murai {
475897f9429SBrian Somers   /* We're now down */
476e1e8b15eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
477e1e8b15eSBrian Somers   struct ccp_opt *next;
478e1e8b15eSBrian Somers 
4793a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
480e1e8b15eSBrian Somers 
481e1e8b15eSBrian Somers   /*
482e1e8b15eSBrian Somers    * Nuke options that may be left over from sending a REQ but never
483e1e8b15eSBrian Somers    * coming up.
484e1e8b15eSBrian Somers    */
485e1e8b15eSBrian Somers   while (ccp->out.opt) {
486e1e8b15eSBrian Somers     next = ccp->out.opt->next;
487e1e8b15eSBrian Somers     free(ccp->out.opt);
488e1e8b15eSBrian Somers     ccp->out.opt = next;
489e1e8b15eSBrian Somers   }
4906cf6ee76SBrian Somers 
4916cf6ee76SBrian Somers   if (ccp_Required(ccp)) {
4926cf6ee76SBrian Somers     if (fp->link->lcp.fsm.state == ST_OPENED)
4936cf6ee76SBrian Somers       log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
4946cf6ee76SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
4956cf6ee76SBrian Somers   }
496af57ed9fSAtsushi Murai }
497af57ed9fSAtsushi Murai 
4983377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
4996f384573SBrian Somers static int
500944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
501af57ed9fSAtsushi Murai {
5027308ec68SBrian Somers   /* We're now up */
503aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
504e1e8b15eSBrian Somers   struct ccp_opt **o;
505057f1760SBrian Somers   unsigned f, fail;
5066301d506SBrian Somers 
5076301d506SBrian Somers   for (f = fail = 0; f < NALGORITHMS; f++)
5086301d506SBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
5096301d506SBrian Somers         (*algorithm[f]->Required)(&ccp->fsm) &&
510057f1760SBrian Somers         (ccp->in.algorithm != (int)f || ccp->out.algorithm != (int)f)) {
5116301d506SBrian Somers       /* Blow it all away - we haven't negotiated a required algorithm */
5126301d506SBrian Somers       log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
5136301d506SBrian Somers                  fp->link->name, protoname(algorithm[f]->id));
5146301d506SBrian Somers       fail = 1;
5156301d506SBrian Somers     }
5166301d506SBrian Somers 
5176301d506SBrian Somers   if (fail) {
5186301d506SBrian Somers     ccp->his_proto = ccp->my_proto = -1;
5196301d506SBrian Somers     fsm_Close(fp);
5206301d506SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
5216301d506SBrian Somers     return 0;
5226301d506SBrian Somers   }
523479508cfSBrian Somers 
5243a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
525479508cfSBrian Somers 
52603036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
527057f1760SBrian Somers       ccp->in.algorithm < (int)NALGORITHMS) {
5288fb5ef5aSBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
5298fb5ef5aSBrian Somers       (fp->bundle, &ccp->in.opt);
53003036ec7SBrian Somers     if (ccp->in.state == NULL) {
531dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
532d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
53383d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
534dd7e2610SBrian Somers       fsm_Close(fp);
535479508cfSBrian Somers       return 0;
53679d1bdaeSBrian Somers     }
537af57ed9fSAtsushi Murai   }
538af57ed9fSAtsushi Murai 
539e1e8b15eSBrian Somers   o = &ccp->out.opt;
540057f1760SBrian Somers   if (ccp->out.algorithm > 0)
541057f1760SBrian Somers     for (f = 0; f < (unsigned)ccp->out.algorithm; f++)
542e1e8b15eSBrian Somers       if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
543e1e8b15eSBrian Somers 	o = &(*o)->next;
544e1e8b15eSBrian Somers 
54503036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
546057f1760SBrian Somers       ccp->out.algorithm < (int)NALGORITHMS) {
5478fb5ef5aSBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
5488fb5ef5aSBrian Somers       (fp->bundle, &(*o)->val);
54903036ec7SBrian Somers     if (ccp->out.state == NULL) {
550dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
551d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
55283d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
553dd7e2610SBrian Somers       fsm_Close(fp);
554479508cfSBrian Somers       return 0;
555247ab36dSBrian Somers     }
556af57ed9fSAtsushi Murai   }
557af57ed9fSAtsushi Murai 
558479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
559479508cfSBrian Somers 
560dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
561d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
56283d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
563479508cfSBrian Somers 
5646f384573SBrian Somers   return 1;
565af57ed9fSAtsushi Murai }
566af57ed9fSAtsushi Murai 
567af57ed9fSAtsushi Murai static void
568ff360cc9SBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
56930c2f2ffSBrian Somers                 struct fsm_decode *dec)
570af57ed9fSAtsushi Murai {
5717308ec68SBrian Somers   /* Deal with incoming data */
572aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
573ff360cc9SBrian Somers   int f;
574ff360cc9SBrian Somers   const char *disp;
575ff360cc9SBrian Somers   struct fsm_opt *opt;
576af57ed9fSAtsushi Murai 
57731516407SBrian Somers   if (mode_type == MODE_REQ)
57831516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
57931516407SBrian Somers 
580057f1760SBrian Somers   while (end >= cp + sizeof(opt->hdr)) {
581ff360cc9SBrian Somers     if ((opt = fsm_readopt(&cp)) == NULL)
582d47dceb8SBrian Somers       break;
583af57ed9fSAtsushi Murai 
5840053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
585ff360cc9SBrian Somers       if (algorithm[f]->id == opt->hdr.id)
5860053cc58SBrian Somers         break;
587af57ed9fSAtsushi Murai 
588ff360cc9SBrian Somers     disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
589ff360cc9SBrian Somers     if (disp == NULL)
590ff360cc9SBrian Somers       disp = "";
59103036ec7SBrian Somers 
592ff360cc9SBrian Somers     log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
593ff360cc9SBrian Somers                opt->hdr.len, disp);
59403036ec7SBrian Somers 
5950053cc58SBrian Somers     if (f == -1) {
5960053cc58SBrian Somers       /* Don't understand that :-( */
5970053cc58SBrian Somers       if (mode_type == MODE_REQ) {
598ff360cc9SBrian Somers         ccp->my_reject |= (1 << opt->hdr.id);
599ff360cc9SBrian Somers         fsm_rej(dec, opt);
6000053cc58SBrian Somers       }
6010053cc58SBrian Somers     } else {
60203036ec7SBrian Somers       struct ccp_opt *o;
6030053cc58SBrian Somers 
6049780ef31SBrian Somers       switch (mode_type) {
605af57ed9fSAtsushi Murai       case MODE_REQ:
6061342caedSBrian Somers         if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
6077f89db65SBrian Somers             (*algorithm[f]->Usable)(fp) &&
6081342caedSBrian Somers             ccp->in.algorithm == -1) {
609ff360cc9SBrian Somers           memcpy(&ccp->in.opt, opt, opt->hdr.len);
6108fb5ef5aSBrian Somers           switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
6110053cc58SBrian Somers           case MODE_REJ:
612ff360cc9SBrian Somers             fsm_rej(dec, &ccp->in.opt);
6130053cc58SBrian Somers             break;
6140053cc58SBrian Somers           case MODE_NAK:
615ff360cc9SBrian Somers             fsm_nak(dec, &ccp->in.opt);
6160053cc58SBrian Somers             break;
6170053cc58SBrian Somers           case MODE_ACK:
618ff360cc9SBrian Somers             fsm_ack(dec, &ccp->in.opt);
619ff360cc9SBrian Somers             ccp->his_proto = opt->hdr.id;
620057f1760SBrian Somers             ccp->in.algorithm = (int)f;		/* This one'll do :-) */
6210053cc58SBrian Somers             break;
6220053cc58SBrian Somers           }
623af57ed9fSAtsushi Murai         } else {
624ff360cc9SBrian Somers           fsm_rej(dec, opt);
625af57ed9fSAtsushi Murai         }
626af57ed9fSAtsushi Murai         break;
627af57ed9fSAtsushi Murai       case MODE_NAK:
62803036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
629ff360cc9SBrian Somers           if (o->val.hdr.id == opt->hdr.id)
63003036ec7SBrian Somers             break;
63103036ec7SBrian Somers         if (o == NULL)
6329b996792SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
6339b996792SBrian Somers                      " option\n", fp->link->name);
6340053cc58SBrian Somers         else {
635ff360cc9SBrian Somers           memcpy(&o->val, opt, opt->hdr.len);
6368fb5ef5aSBrian Somers           if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
6378fb5ef5aSBrian Somers               MODE_ACK)
63883d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
6391ae349f5Scvs2svn           else {
640ff360cc9SBrian Somers             ccp->his_reject |= (1 << opt->hdr.id);
64183d1af55SBrian Somers             ccp->my_proto = -1;
6426cf6ee76SBrian Somers             if (algorithm[f]->Required(fp)) {
6436cf6ee76SBrian Somers               log_Printf(LogWARN, "%s: Cannot understand peers (required)"
6446cf6ee76SBrian Somers                          " %s negotiation\n", fp->link->name,
6456cf6ee76SBrian Somers                          protoname(algorithm[f]->id));
6466cf6ee76SBrian Somers               fsm_Close(&fp->link->lcp.fsm);
6476cf6ee76SBrian Somers             }
6481ae349f5Scvs2svn           }
6490053cc58SBrian Somers         }
6500053cc58SBrian Somers         break;
651af57ed9fSAtsushi Murai       case MODE_REJ:
652ff360cc9SBrian Somers         ccp->his_reject |= (1 << opt->hdr.id);
65383d1af55SBrian Somers         ccp->my_proto = -1;
6546cf6ee76SBrian Somers         if (algorithm[f]->Required(fp)) {
6556cf6ee76SBrian Somers           log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
6566cf6ee76SBrian Somers                      fp->link->name, protoname(algorithm[f]->id));
6576cf6ee76SBrian Somers           fsm_Close(&fp->link->lcp.fsm);
6586cf6ee76SBrian Somers         }
659af57ed9fSAtsushi Murai         break;
660af57ed9fSAtsushi Murai       }
661af57ed9fSAtsushi Murai     }
662af57ed9fSAtsushi Murai   }
6630053cc58SBrian Somers 
664e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
665ff360cc9SBrian Somers     fsm_opt_normalise(dec);
666ff360cc9SBrian Somers     if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
66703036ec7SBrian Somers       if (ccp->in.state == NULL) {
66803036ec7SBrian Somers         ccp->his_proto = -1;
66903036ec7SBrian Somers         ccp->in.algorithm = -1;
670247ab36dSBrian Somers       }
6711ae349f5Scvs2svn     }
6720053cc58SBrian Somers   }
673af57ed9fSAtsushi Murai }
674af57ed9fSAtsushi Murai 
6755d9e6103SBrian Somers extern struct mbuf *
6765d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
677af57ed9fSAtsushi Murai {
6787308ec68SBrian Somers   /* Got PROTO_CCP from link */
67926af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
680455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
6815d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
682af57ed9fSAtsushi Murai   else {
683641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
684dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
6855d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
68626af0ae9SBrian Somers     m_freem(bp);
687af57ed9fSAtsushi Murai   }
6885d9e6103SBrian Somers   return NULL;
689af57ed9fSAtsushi Murai }
6900053cc58SBrian Somers 
691503a7782SBrian Somers static void
692503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
6930053cc58SBrian Somers {
6947308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
695f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
696f4768038SBrian Somers 
697f4768038SBrian Somers   if (ccp->reset_sent != -1) {
698f4768038SBrian Somers     if (id != ccp->reset_sent) {
699a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
700d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
70198baf7c8SBrian Somers       return;
70298baf7c8SBrian Somers     }
70398baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
704f4768038SBrian Somers   } else if (id == ccp->last_reset)
705dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
706d47dceb8SBrian Somers                fp->link->name);
70798baf7c8SBrian Somers   else {
708a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
709d47dceb8SBrian Somers                fp->link->name, id);
71098baf7c8SBrian Somers     return;
71198baf7c8SBrian Somers   }
71298baf7c8SBrian Somers 
713f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
714f4768038SBrian Somers   ccp->reset_sent = -1;
71503036ec7SBrian Somers   if (ccp->in.state != NULL)
71603036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
7170053cc58SBrian Somers }
7180053cc58SBrian Somers 
7195d9e6103SBrian Somers static struct mbuf *
720057f1760SBrian Somers ccp_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp,
7215d9e6103SBrian Somers               int pri, u_short *proto)
7220053cc58SBrian Somers {
7236cf6ee76SBrian Somers   if (PROTO_COMPRESSIBLE(*proto)) {
7246cf6ee76SBrian Somers     if (l->ccp.fsm.state != ST_OPENED) {
7256cf6ee76SBrian Somers       if (ccp_Required(&l->ccp)) {
7266cf6ee76SBrian Somers         /* The NCP layer shouldn't have let this happen ! */
7276cf6ee76SBrian Somers         log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
7286cf6ee76SBrian Somers                    " required CCP layer\n", l->name);
7296cf6ee76SBrian Somers         m_freem(bp);
7306cf6ee76SBrian Somers         bp = NULL;
7316cf6ee76SBrian Somers       }
7326cf6ee76SBrian Somers     } else if (l->ccp.out.state != NULL) {
733411675baSBrian Somers       bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
7345d9e6103SBrian Somers              (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
735411675baSBrian Somers       switch (*proto) {
736411675baSBrian Somers         case PROTO_ICOMPD:
73726af0ae9SBrian Somers           m_settype(bp, MB_ICOMPDOUT);
738411675baSBrian Somers           break;
739411675baSBrian Somers         case PROTO_COMPD:
74026af0ae9SBrian Somers           m_settype(bp, MB_COMPDOUT);
741411675baSBrian Somers           break;
742411675baSBrian Somers       }
743411675baSBrian Somers     }
7446cf6ee76SBrian Somers   }
7455d9e6103SBrian Somers 
7465d9e6103SBrian Somers   return bp;
7470053cc58SBrian Somers }
7480053cc58SBrian Somers 
7495d9e6103SBrian Somers static struct mbuf *
750057f1760SBrian Somers ccp_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp,
751057f1760SBrian Somers 	      u_short *proto)
7520053cc58SBrian Somers {
753ee6c193fSBrian Somers   /*
754ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
755ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
756ee6c193fSBrian Somers    */
7575d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
758ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
7597308ec68SBrian Somers       /* Decompress incoming data */
7605d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
76198baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
762411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
763411675baSBrian Somers                    MB_CCPOUT);
764411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
765411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
7665d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
767411675baSBrian Somers         switch (*proto) {
768411675baSBrian Somers           case PROTO_ICOMPD:
76926af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
770411675baSBrian Somers             break;
771411675baSBrian Somers           case PROTO_COMPD:
77226af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
773411675baSBrian Somers             break;
774411675baSBrian Somers         }
775411675baSBrian Somers         return bp;
776411675baSBrian Somers       }
77726af0ae9SBrian Somers       m_freem(bp);
778ee6c193fSBrian Somers       bp = NULL;
7796815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
780ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
7815d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
7825d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
783e0efa796SBrian Somers     }
7840053cc58SBrian Somers   }
7850053cc58SBrian Somers 
786ee6c193fSBrian Somers   return bp;
7871ae349f5Scvs2svn }
788ed32233cSBrian Somers 
789ed32233cSBrian Somers u_short
790ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
7910053cc58SBrian Somers {
792ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
793ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
7940053cc58SBrian Somers }
7951df0a3b9SBrian Somers 
79606337856SBrian Somers int
7971df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
7981df0a3b9SBrian Somers {
7991df0a3b9SBrian Somers   int f;
8001df0a3b9SBrian Somers 
8011df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
80206337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
8031df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
80406337856SBrian Somers       return 1;
80506337856SBrian Somers     }
8061df0a3b9SBrian Somers 
80706337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
80806337856SBrian Somers 
80906337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
81006337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
81106337856SBrian Somers       return 1;
81206337856SBrian Somers 
81306337856SBrian Somers   return 0;				/* No CCP at all */
8141df0a3b9SBrian Somers }
8155d9e6103SBrian Somers 
8167f89db65SBrian Somers int
817057f1760SBrian Somers ccp_DefaultUsable(struct fsm *fp __unused)
8187f89db65SBrian Somers {
8197f89db65SBrian Somers   return 1;
8207f89db65SBrian Somers }
8217f89db65SBrian Somers 
8226cf6ee76SBrian Somers int
823057f1760SBrian Somers ccp_DefaultRequired(struct fsm *fp __unused)
8246cf6ee76SBrian Somers {
8256cf6ee76SBrian Somers   return 0;
8266cf6ee76SBrian Somers }
8276cf6ee76SBrian Somers 
8285d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
829