xref: /freebsd/usr.sbin/ppp/ccp.c (revision 057f1760a8171825b260dad27502f74ed5f69faf)
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>
3530949fd4SBrian Somers #include <sys/socket.h>
361fa665f5SBrian Somers #include <sys/un.h>
3775240ed1SBrian Somers 
386eafd353SBrian Somers #include <stdarg.h>
3975240ed1SBrian Somers #include <stdio.h>
4003036ec7SBrian Somers #include <stdlib.h>
41eb6e5e05SBrian Somers #include <string.h>	/* memcpy() on some archs */
4285b542cfSBrian Somers #include <termios.h>
4375240ed1SBrian Somers 
445d9e6103SBrian Somers #include "layer.h"
45c9e11a11SBrian Somers #include "defs.h"
46b6e82f33SBrian Somers #include "command.h"
4775240ed1SBrian Somers #include "mbuf.h"
4875240ed1SBrian Somers #include "log.h"
4975240ed1SBrian Somers #include "timer.h"
50af57ed9fSAtsushi Murai #include "fsm.h"
515d9e6103SBrian Somers #include "proto.h"
52ed6a16c1SPoul-Henning Kamp #include "pred.h"
530053cc58SBrian Somers #include "deflate.h"
545828db6dSBrian Somers #include "throughput.h"
555828db6dSBrian Somers #include "iplist.h"
56eaa4df37SBrian Somers #include "slcompress.h"
575a72b6edSBrian Somers #include "lqr.h"
585a72b6edSBrian Somers #include "hdlc.h"
591038894eSBrian Somers #include "lcp.h"
601038894eSBrian Somers #include "ccp.h"
6130949fd4SBrian Somers #include "ncpaddr.h"
625828db6dSBrian Somers #include "ipcp.h"
635ca5389aSBrian Somers #include "filter.h"
6485b542cfSBrian Somers #include "descriptor.h"
6585b542cfSBrian Somers #include "prompt.h"
66503a7782SBrian Somers #include "link.h"
673b0f8d2eSBrian Somers #include "mp.h"
68ed32233cSBrian Somers #include "async.h"
69ed32233cSBrian Somers #include "physical.h"
70972a1bcfSBrian Somers #ifndef NORADIUS
71972a1bcfSBrian Somers #include "radius.h"
72972a1bcfSBrian Somers #endif
73fb11a9c2SBrian Somers #ifndef NODES
74a8d604abSBrian Somers #include "mppe.h"
75a8d604abSBrian Somers #endif
7630949fd4SBrian Somers #include "ipv6cp.h"
7730949fd4SBrian Somers #include "ncp.h"
783b0f8d2eSBrian Somers #include "bundle.h"
79af57ed9fSAtsushi Murai 
80927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
812267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
822267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
83ff360cc9SBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
8430c2f2ffSBrian Somers                             struct fsm_decode *);
85927145beSBrian Somers static void CcpLayerStart(struct fsm *);
86927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
876f384573SBrian Somers static int CcpLayerUp(struct fsm *);
88927145beSBrian Somers static void CcpLayerDown(struct fsm *);
89479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int);
906cf6ee76SBrian Somers static int CcpRecvResetReq(struct fsm *);
91503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
92af57ed9fSAtsushi Murai 
9383d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
94af57ed9fSAtsushi Murai   CcpLayerUp,
95af57ed9fSAtsushi Murai   CcpLayerDown,
96af57ed9fSAtsushi Murai   CcpLayerStart,
97af57ed9fSAtsushi Murai   CcpLayerFinish,
98af57ed9fSAtsushi Murai   CcpInitRestartCounter,
99af57ed9fSAtsushi Murai   CcpSendConfigReq,
1002267893fSBrian Somers   CcpSentTerminateReq,
101af57ed9fSAtsushi Murai   CcpSendTerminateAck,
102af57ed9fSAtsushi Murai   CcpDecodeConfig,
103503a7782SBrian Somers   CcpRecvResetReq,
104503a7782SBrian Somers   CcpRecvResetAck
105af57ed9fSAtsushi Murai };
106af57ed9fSAtsushi Murai 
107182c898aSBrian Somers static const char * const ccp_TimerNames[] =
1086f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
1096f384573SBrian Somers 
110d6d3eeabSBrian Somers static const char *
111d6d3eeabSBrian Somers protoname(int proto)
112d6d3eeabSBrian Somers {
113182c898aSBrian Somers   static char const * const cftypes[] = {
114d6d3eeabSBrian Somers     /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
1159e836af5SBrian Somers     "OUI",		/* 0: OUI */
1169e836af5SBrian Somers     "PRED1",		/* 1: Predictor type 1 */
1179e836af5SBrian Somers     "PRED2",		/* 2: Predictor type 2 */
1189e836af5SBrian Somers     "PUDDLE",		/* 3: Puddle Jumber */
119d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
120d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
1219e836af5SBrian Somers     "HWPPC",		/* 16: Hewlett-Packard PPC */
1224bc84b8cSBrian Somers     "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
123a8d604abSBrian Somers     "MPPE",		/* 18: Microsoft PPC (rfc2118) and */
124a8d604abSBrian Somers 			/*     Microsoft PPE (draft-ietf-pppext-mppe) */
1254bc84b8cSBrian Somers     "GAND",		/* 19: Gandalf FZA (rfc1993) */
126b6e82f33SBrian Somers     "V42BIS",		/* 20: ARG->DATA.42bis compression */
1270053cc58SBrian Somers     "BSD",		/* 21: BSD LZW Compress */
128d6d3eeabSBrian Somers     NULL,
1294bc84b8cSBrian Somers     "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1304bc84b8cSBrian Somers     "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
1311342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1324bc84b8cSBrian Somers     "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1334bc84b8cSBrian Somers     "DEFLATE",		/* 26: Deflate (rfc1979) */
134af57ed9fSAtsushi Murai   };
135af57ed9fSAtsushi Murai 
136057f1760SBrian Somers   if (proto < 0 || (unsigned)proto > sizeof cftypes / sizeof *cftypes ||
1379ea69707SBrian Somers       cftypes[proto] == NULL) {
1389ea69707SBrian Somers     if (proto == -1)
1399ea69707SBrian Somers       return "none";
140d6d3eeabSBrian Somers     return HexStr(proto, NULL, 0);
1419ea69707SBrian Somers   }
1429e836af5SBrian Somers 
1430053cc58SBrian Somers   return cftypes[proto];
1440053cc58SBrian Somers }
1450053cc58SBrian Somers 
1464bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
147182c898aSBrian Somers static const struct ccp_algorithm * const algorithm[] = {
1484bc84b8cSBrian Somers   &DeflateAlgorithm,
1490053cc58SBrian Somers   &Pred1Algorithm,
1504bc84b8cSBrian Somers   &PppdDeflateAlgorithm
151fb11a9c2SBrian Somers #ifndef NODES
152a8d604abSBrian Somers   , &MPPEAlgorithm
153a8d604abSBrian Somers #endif
1540053cc58SBrian Somers };
1550053cc58SBrian Somers 
15670ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1570053cc58SBrian Somers 
158274e766cSBrian Somers int
159503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
160af57ed9fSAtsushi Murai {
1616cf6ee76SBrian Somers   struct ccp_opt **o;
162dd0645c5SBrian Somers   struct link *l;
163dd0645c5SBrian Somers   struct ccp *ccp;
1646cf6ee76SBrian Somers   int f;
165dd0645c5SBrian Somers 
1663a2e4f62SBrian Somers   l = command_ChooseLink(arg);
167dd0645c5SBrian Somers   ccp = &l->ccp;
168503a7782SBrian Somers 
169b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1701e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
1715d9e6103SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
172b6217683SBrian Somers     prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
173503a7782SBrian Somers                   protoname(ccp->my_proto), protoname(ccp->his_proto));
174b6217683SBrian Somers     prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
175503a7782SBrian Somers                   ccp->uncompout, ccp->compout,
176503a7782SBrian Somers                   ccp->compin, ccp->uncompin);
1775d9e6103SBrian Somers   }
178cd9647a1SBrian Somers 
1796cf6ee76SBrian Somers   if (ccp->in.algorithm != -1)
1806cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "\n Input Options:  %s\n",
1816cf6ee76SBrian Somers                   (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt));
1826cf6ee76SBrian Somers 
1836cf6ee76SBrian Somers   if (ccp->out.algorithm != -1) {
1846cf6ee76SBrian Somers     o = &ccp->out.opt;
1856cf6ee76SBrian Somers     for (f = 0; f < ccp->out.algorithm; f++)
1866cf6ee76SBrian Somers       if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
1876cf6ee76SBrian Somers         o = &(*o)->next;
1886cf6ee76SBrian Somers     prompt_Printf(arg->prompt, " Output Options: %s\n",
1896cf6ee76SBrian Somers                   (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val));
1906cf6ee76SBrian Somers   }
1916cf6ee76SBrian Somers 
192b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
193479508cfSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
194479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
195479508cfSBrian Somers                 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
196479508cfSBrian Somers                 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
197b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
198b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
199b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
200fb11a9c2SBrian Somers #ifndef NODES
2016cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "           MPPE: ");
2026cf6ee76SBrian Somers   if (ccp->cfg.mppe.keybits)
2036cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits);
2046cf6ee76SBrian Somers   else
2056cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "any bits, ");
2066cf6ee76SBrian Somers   switch (ccp->cfg.mppe.state) {
2076cf6ee76SBrian Somers   case MPPE_STATEFUL:
20880a18377SBrian Somers     prompt_Printf(arg->prompt, "stateful");
2096cf6ee76SBrian Somers     break;
2106cf6ee76SBrian Somers   case MPPE_STATELESS:
2116cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "stateless");
2126cf6ee76SBrian Somers     break;
2136cf6ee76SBrian Somers   case MPPE_ANYSTATE:
2146cf6ee76SBrian Somers     prompt_Printf(arg->prompt, "any state");
2156cf6ee76SBrian Somers     break;
2166cf6ee76SBrian Somers   }
2176cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "%s\n",
2186cf6ee76SBrian Somers                 ccp->cfg.mppe.required ? ", required" : "");
2196cf6ee76SBrian Somers #endif
2206cf6ee76SBrian Somers 
2216cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "\n           DEFLATE:    %s\n",
2221342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
2231342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
2241342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
2251342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
2261342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
227fb11a9c2SBrian Somers #ifndef NODES
2286cf6ee76SBrian Somers   prompt_Printf(arg->prompt, "           MPPE:       %s\n",
229a8d604abSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
230a8d604abSBrian Somers #endif
231274e766cSBrian Somers   return 0;
232af57ed9fSAtsushi Murai }
233af57ed9fSAtsushi Murai 
2341ae349f5Scvs2svn void
2356f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
236af57ed9fSAtsushi Murai {
2376f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
2386f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
2396f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
2406f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
241ea661041SBrian Somers }
242ea661041SBrian Somers 
243ea661041SBrian Somers void
2446d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
2456d666775SBrian Somers          const struct fsm_parent *parent)
246ea661041SBrian Somers {
2477308ec68SBrian Somers   /* Initialise ourselves */
2483b0f8d2eSBrian Somers 
249479508cfSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
2506f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
251cd9647a1SBrian Somers 
25203036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
25303036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
254479508cfSBrian Somers   ccp->cfg.fsm.timeout = DEF_FSMRETRY;
255479508cfSBrian Somers   ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
256479508cfSBrian Somers   ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
2571342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
2581342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
2591342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
260fb11a9c2SBrian Somers #ifndef NODES
2616cf6ee76SBrian Somers   ccp->cfg.mppe.keybits = 0;
2626cf6ee76SBrian Somers   ccp->cfg.mppe.state = MPPE_ANYSTATE;
2636cf6ee76SBrian Somers   ccp->cfg.mppe.required = 0;
264385167a6SBrian Somers   ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
265a8d604abSBrian Somers #endif
266cd9647a1SBrian Somers 
267503a7782SBrian Somers   ccp_Setup(ccp);
268503a7782SBrian Somers }
269503a7782SBrian Somers 
270503a7782SBrian Somers void
271503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
272503a7782SBrian Somers {
273503a7782SBrian Somers   /* Set ourselves up for a startup */
274503a7782SBrian Somers   ccp->fsm.open_mode = 0;
275503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
276503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
27703036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
27803036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
279ff360cc9SBrian Somers   ccp->in.opt.hdr.id = -1;
28003036ec7SBrian Somers   ccp->out.opt = NULL;
281503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
282503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
283503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
284af57ed9fSAtsushi Murai }
285af57ed9fSAtsushi Murai 
2866cf6ee76SBrian Somers /*
2876cf6ee76SBrian Somers  * Is ccp *REQUIRED* ?
2886cf6ee76SBrian Somers  * We ask each of the configured ccp protocols if they're required and
2896cf6ee76SBrian Somers  * return TRUE if they are.
2906cf6ee76SBrian Somers  *
2916cf6ee76SBrian Somers  * It's not possible for the peer to reject a required ccp protocol
2926cf6ee76SBrian Somers  * without our state machine bringing the supporting lcp layer down.
2936cf6ee76SBrian Somers  *
2946cf6ee76SBrian Somers  * If ccp is required but not open, the NCP layer should not push
2956cf6ee76SBrian Somers  * any data into the link.
2966cf6ee76SBrian Somers  */
2976cf6ee76SBrian Somers int
2986cf6ee76SBrian Somers ccp_Required(struct ccp *ccp)
2996cf6ee76SBrian Somers {
300057f1760SBrian Somers   unsigned f;
3016cf6ee76SBrian Somers 
3026cf6ee76SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
3036cf6ee76SBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
3046cf6ee76SBrian Somers         (*algorithm[f]->Required)(&ccp->fsm))
3056cf6ee76SBrian Somers       return 1;
3066cf6ee76SBrian Somers 
3076cf6ee76SBrian Somers   return 0;
3086cf6ee76SBrian Somers }
3096cf6ee76SBrian Somers 
3106301d506SBrian Somers /*
3116301d506SBrian Somers  * Report whether it's possible to increase a packet's size after
3126301d506SBrian Somers  * compression (and by how much).
3136301d506SBrian Somers  */
3146301d506SBrian Somers int
3156301d506SBrian Somers ccp_MTUOverhead(struct ccp *ccp)
3166301d506SBrian Somers {
3177e62c638SBrian Somers   if (ccp->fsm.state == ST_OPENED && ccp->out.algorithm >= 0)
3186301d506SBrian Somers     return algorithm[ccp->out.algorithm]->o.MTUOverhead;
3196301d506SBrian Somers 
3206301d506SBrian Somers   return 0;
3216301d506SBrian Somers }
3226301d506SBrian Somers 
323af57ed9fSAtsushi Murai static void
324479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what)
325af57ed9fSAtsushi Murai {
3267308ec68SBrian Somers   /* Set fsm timer load */
327cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
328cd9647a1SBrian Somers 
329479508cfSBrian Somers   fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
330479508cfSBrian Somers   switch (what) {
331479508cfSBrian Somers     case FSM_REQ_TIMER:
332479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxreq;
333479508cfSBrian Somers       break;
334479508cfSBrian Somers     case FSM_TRM_TIMER:
335479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxtrm;
336479508cfSBrian Somers       break;
337479508cfSBrian Somers     default:
338479508cfSBrian Somers       fp->restart = 1;
339479508cfSBrian Somers       break;
340479508cfSBrian Somers   }
341af57ed9fSAtsushi Murai }
342af57ed9fSAtsushi Murai 
343af57ed9fSAtsushi Murai static void
344944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
345af57ed9fSAtsushi Murai {
3467308ec68SBrian Somers   /* Send config REQ please */
347aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
34803036ec7SBrian Somers   struct ccp_opt **o;
34930c2f2ffSBrian Somers   u_char *cp, buff[100];
350057f1760SBrian Somers   unsigned f;
351057f1760SBrian Somers   int alloc;
352af57ed9fSAtsushi Murai 
35330c2f2ffSBrian Somers   cp = buff;
35403036ec7SBrian Somers   o = &ccp->out.opt;
35503036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
35683d1af55SBrian Somers   ccp->my_proto = -1;
35703036ec7SBrian Somers   ccp->out.algorithm = -1;
3580053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
3591342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
3607f89db65SBrian Somers         !REJECTED(ccp, algorithm[f]->id) &&
3617f89db65SBrian Somers         (*algorithm[f]->Usable)(fp)) {
3620053cc58SBrian Somers 
363ba081e43SBrian Somers       if (!alloc)
364ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
365057f1760SBrian Somers           if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == (int)f)
366ba081e43SBrian Somers             break;
367ba081e43SBrian Somers 
368ba081e43SBrian Somers       if (alloc || *o == NULL) {
36903036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
370ff360cc9SBrian Somers         (*o)->val.hdr.id = algorithm[f]->id;
371ff360cc9SBrian Somers         (*o)->val.hdr.len = 2;
37203036ec7SBrian Somers         (*o)->next = NULL;
37303036ec7SBrian Somers         (*o)->algorithm = f;
3748fb5ef5aSBrian Somers         (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
375af57ed9fSAtsushi Murai       }
3761ae349f5Scvs2svn 
377ff360cc9SBrian Somers       if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
378dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
37930c2f2ffSBrian Somers         break;
38030c2f2ffSBrian Somers       }
381ff360cc9SBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.hdr.len);
382ff360cc9SBrian Somers       cp += (*o)->val.hdr.len;
38303036ec7SBrian Somers 
384ff360cc9SBrian Somers       ccp->my_proto = (*o)->val.hdr.id;
38503036ec7SBrian Somers       ccp->out.algorithm = f;
38603036ec7SBrian Somers 
38703036ec7SBrian Somers       if (alloc)
38803036ec7SBrian Somers         o = &(*o)->next;
3891ae349f5Scvs2svn     }
3902267893fSBrian Somers 
391411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
392af57ed9fSAtsushi Murai }
393af57ed9fSAtsushi Murai 
394af57ed9fSAtsushi Murai void
395dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
396af57ed9fSAtsushi Murai {
3977308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
398aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3992267893fSBrian Somers 
40083d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
40183d1af55SBrian Somers   ccp->last_reset = -1;
402411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
403af57ed9fSAtsushi Murai }
404af57ed9fSAtsushi Murai 
405af57ed9fSAtsushi Murai static void
406057f1760SBrian Somers CcpSentTerminateReq(struct fsm *fp __unused)
407af57ed9fSAtsushi Murai {
4087308ec68SBrian Somers   /* Term REQ just sent by FSM */
409af57ed9fSAtsushi Murai }
410af57ed9fSAtsushi Murai 
411af57ed9fSAtsushi Murai static void
4122267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
413af57ed9fSAtsushi Murai {
4147308ec68SBrian Somers   /* Send Term ACK please */
415411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
416af57ed9fSAtsushi Murai }
417af57ed9fSAtsushi Murai 
4186cf6ee76SBrian Somers static int
419944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
420af57ed9fSAtsushi Murai {
4217308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
422aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
4236cf6ee76SBrian Somers   if (ccp->out.state == NULL)
4246cf6ee76SBrian Somers     return 1;
4256cf6ee76SBrian Somers   return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
426af57ed9fSAtsushi Murai }
427af57ed9fSAtsushi Murai 
428af57ed9fSAtsushi Murai static void
429944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
430af57ed9fSAtsushi Murai {
4317308ec68SBrian Somers   /* We're about to start up ! */
432479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
433479508cfSBrian Somers 
4343a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
435479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
436af57ed9fSAtsushi Murai }
437af57ed9fSAtsushi Murai 
438af57ed9fSAtsushi Murai static void
439897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
440af57ed9fSAtsushi Murai {
441897f9429SBrian Somers   /* About to come down */
442aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
443ba081e43SBrian Somers   struct ccp_opt *next;
444ba081e43SBrian Somers 
4453a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
44603036ec7SBrian Somers   if (ccp->in.state != NULL) {
44703036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
44803036ec7SBrian Somers     ccp->in.state = NULL;
4498d9b9867SBrian Somers     ccp->in.algorithm = -1;
4507308ec68SBrian Somers   }
45103036ec7SBrian Somers   if (ccp->out.state != NULL) {
45203036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
45303036ec7SBrian Somers     ccp->out.state = NULL;
4548d9b9867SBrian Somers     ccp->out.algorithm = -1;
4557308ec68SBrian Somers   }
4568d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
457ba081e43SBrian Somers 
458ba081e43SBrian Somers   while (ccp->out.opt) {
459ba081e43SBrian Somers     next = ccp->out.opt->next;
460ba081e43SBrian Somers     free(ccp->out.opt);
461ba081e43SBrian Somers     ccp->out.opt = next;
462ba081e43SBrian Somers   }
463897f9429SBrian Somers   ccp_Setup(ccp);
464af57ed9fSAtsushi Murai }
465af57ed9fSAtsushi Murai 
466af57ed9fSAtsushi Murai static void
467897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
468af57ed9fSAtsushi Murai {
469897f9429SBrian Somers   /* We're now down */
470e1e8b15eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
471e1e8b15eSBrian Somers   struct ccp_opt *next;
472e1e8b15eSBrian Somers 
4733a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
474e1e8b15eSBrian Somers 
475e1e8b15eSBrian Somers   /*
476e1e8b15eSBrian Somers    * Nuke options that may be left over from sending a REQ but never
477e1e8b15eSBrian Somers    * coming up.
478e1e8b15eSBrian Somers    */
479e1e8b15eSBrian Somers   while (ccp->out.opt) {
480e1e8b15eSBrian Somers     next = ccp->out.opt->next;
481e1e8b15eSBrian Somers     free(ccp->out.opt);
482e1e8b15eSBrian Somers     ccp->out.opt = next;
483e1e8b15eSBrian Somers   }
4846cf6ee76SBrian Somers 
4856cf6ee76SBrian Somers   if (ccp_Required(ccp)) {
4866cf6ee76SBrian Somers     if (fp->link->lcp.fsm.state == ST_OPENED)
4876cf6ee76SBrian Somers       log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
4886cf6ee76SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
4896cf6ee76SBrian Somers   }
490af57ed9fSAtsushi Murai }
491af57ed9fSAtsushi Murai 
4923377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
4936f384573SBrian Somers static int
494944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
495af57ed9fSAtsushi Murai {
4967308ec68SBrian Somers   /* We're now up */
497aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
498e1e8b15eSBrian Somers   struct ccp_opt **o;
499057f1760SBrian Somers   unsigned f, fail;
5006301d506SBrian Somers 
5016301d506SBrian Somers   for (f = fail = 0; f < NALGORITHMS; f++)
5026301d506SBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
5036301d506SBrian Somers         (*algorithm[f]->Required)(&ccp->fsm) &&
504057f1760SBrian Somers         (ccp->in.algorithm != (int)f || ccp->out.algorithm != (int)f)) {
5056301d506SBrian Somers       /* Blow it all away - we haven't negotiated a required algorithm */
5066301d506SBrian Somers       log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
5076301d506SBrian Somers                  fp->link->name, protoname(algorithm[f]->id));
5086301d506SBrian Somers       fail = 1;
5096301d506SBrian Somers     }
5106301d506SBrian Somers 
5116301d506SBrian Somers   if (fail) {
5126301d506SBrian Somers     ccp->his_proto = ccp->my_proto = -1;
5136301d506SBrian Somers     fsm_Close(fp);
5146301d506SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
5156301d506SBrian Somers     return 0;
5166301d506SBrian Somers   }
517479508cfSBrian Somers 
5183a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
519479508cfSBrian Somers 
52003036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
521057f1760SBrian Somers       ccp->in.algorithm < (int)NALGORITHMS) {
5228fb5ef5aSBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
5238fb5ef5aSBrian Somers       (fp->bundle, &ccp->in.opt);
52403036ec7SBrian Somers     if (ccp->in.state == NULL) {
525dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
526d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
52783d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
528dd7e2610SBrian Somers       fsm_Close(fp);
529479508cfSBrian Somers       return 0;
53079d1bdaeSBrian Somers     }
531af57ed9fSAtsushi Murai   }
532af57ed9fSAtsushi Murai 
533e1e8b15eSBrian Somers   o = &ccp->out.opt;
534057f1760SBrian Somers   if (ccp->out.algorithm > 0)
535057f1760SBrian Somers     for (f = 0; f < (unsigned)ccp->out.algorithm; f++)
536e1e8b15eSBrian Somers       if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
537e1e8b15eSBrian Somers 	o = &(*o)->next;
538e1e8b15eSBrian Somers 
53903036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
540057f1760SBrian Somers       ccp->out.algorithm < (int)NALGORITHMS) {
5418fb5ef5aSBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
5428fb5ef5aSBrian Somers       (fp->bundle, &(*o)->val);
54303036ec7SBrian Somers     if (ccp->out.state == NULL) {
544dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
545d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
54683d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
547dd7e2610SBrian Somers       fsm_Close(fp);
548479508cfSBrian Somers       return 0;
549247ab36dSBrian Somers     }
550af57ed9fSAtsushi Murai   }
551af57ed9fSAtsushi Murai 
552479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
553479508cfSBrian Somers 
554dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
555d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
55683d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
557479508cfSBrian Somers 
5586f384573SBrian Somers   return 1;
559af57ed9fSAtsushi Murai }
560af57ed9fSAtsushi Murai 
561af57ed9fSAtsushi Murai static void
562ff360cc9SBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
56330c2f2ffSBrian Somers                 struct fsm_decode *dec)
564af57ed9fSAtsushi Murai {
5657308ec68SBrian Somers   /* Deal with incoming data */
566aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
567ff360cc9SBrian Somers   int f;
568ff360cc9SBrian Somers   const char *disp;
569ff360cc9SBrian Somers   struct fsm_opt *opt;
570af57ed9fSAtsushi Murai 
57131516407SBrian Somers   if (mode_type == MODE_REQ)
57231516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
57331516407SBrian Somers 
574057f1760SBrian Somers   while (end >= cp + sizeof(opt->hdr)) {
575ff360cc9SBrian Somers     if ((opt = fsm_readopt(&cp)) == NULL)
576d47dceb8SBrian Somers       break;
577af57ed9fSAtsushi Murai 
5780053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
579ff360cc9SBrian Somers       if (algorithm[f]->id == opt->hdr.id)
5800053cc58SBrian Somers         break;
581af57ed9fSAtsushi Murai 
582ff360cc9SBrian Somers     disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
583ff360cc9SBrian Somers     if (disp == NULL)
584ff360cc9SBrian Somers       disp = "";
58503036ec7SBrian Somers 
586ff360cc9SBrian Somers     log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
587ff360cc9SBrian Somers                opt->hdr.len, disp);
58803036ec7SBrian Somers 
5890053cc58SBrian Somers     if (f == -1) {
5900053cc58SBrian Somers       /* Don't understand that :-( */
5910053cc58SBrian Somers       if (mode_type == MODE_REQ) {
592ff360cc9SBrian Somers         ccp->my_reject |= (1 << opt->hdr.id);
593ff360cc9SBrian Somers         fsm_rej(dec, opt);
5940053cc58SBrian Somers       }
5950053cc58SBrian Somers     } else {
59603036ec7SBrian Somers       struct ccp_opt *o;
5970053cc58SBrian Somers 
5989780ef31SBrian Somers       switch (mode_type) {
599af57ed9fSAtsushi Murai       case MODE_REQ:
6001342caedSBrian Somers         if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
6017f89db65SBrian Somers             (*algorithm[f]->Usable)(fp) &&
6021342caedSBrian Somers             ccp->in.algorithm == -1) {
603ff360cc9SBrian Somers           memcpy(&ccp->in.opt, opt, opt->hdr.len);
6048fb5ef5aSBrian Somers           switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
6050053cc58SBrian Somers           case MODE_REJ:
606ff360cc9SBrian Somers             fsm_rej(dec, &ccp->in.opt);
6070053cc58SBrian Somers             break;
6080053cc58SBrian Somers           case MODE_NAK:
609ff360cc9SBrian Somers             fsm_nak(dec, &ccp->in.opt);
6100053cc58SBrian Somers             break;
6110053cc58SBrian Somers           case MODE_ACK:
612ff360cc9SBrian Somers             fsm_ack(dec, &ccp->in.opt);
613ff360cc9SBrian Somers             ccp->his_proto = opt->hdr.id;
614057f1760SBrian Somers             ccp->in.algorithm = (int)f;		/* This one'll do :-) */
6150053cc58SBrian Somers             break;
6160053cc58SBrian Somers           }
617af57ed9fSAtsushi Murai         } else {
618ff360cc9SBrian Somers           fsm_rej(dec, opt);
619af57ed9fSAtsushi Murai         }
620af57ed9fSAtsushi Murai         break;
621af57ed9fSAtsushi Murai       case MODE_NAK:
62203036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
623ff360cc9SBrian Somers           if (o->val.hdr.id == opt->hdr.id)
62403036ec7SBrian Somers             break;
62503036ec7SBrian Somers         if (o == NULL)
6269b996792SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
6279b996792SBrian Somers                      " option\n", fp->link->name);
6280053cc58SBrian Somers         else {
629ff360cc9SBrian Somers           memcpy(&o->val, opt, opt->hdr.len);
6308fb5ef5aSBrian Somers           if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
6318fb5ef5aSBrian Somers               MODE_ACK)
63283d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
6331ae349f5Scvs2svn           else {
634ff360cc9SBrian Somers             ccp->his_reject |= (1 << opt->hdr.id);
63583d1af55SBrian Somers             ccp->my_proto = -1;
6366cf6ee76SBrian Somers             if (algorithm[f]->Required(fp)) {
6376cf6ee76SBrian Somers               log_Printf(LogWARN, "%s: Cannot understand peers (required)"
6386cf6ee76SBrian Somers                          " %s negotiation\n", fp->link->name,
6396cf6ee76SBrian Somers                          protoname(algorithm[f]->id));
6406cf6ee76SBrian Somers               fsm_Close(&fp->link->lcp.fsm);
6416cf6ee76SBrian Somers             }
6421ae349f5Scvs2svn           }
6430053cc58SBrian Somers         }
6440053cc58SBrian Somers         break;
645af57ed9fSAtsushi Murai       case MODE_REJ:
646ff360cc9SBrian Somers         ccp->his_reject |= (1 << opt->hdr.id);
64783d1af55SBrian Somers         ccp->my_proto = -1;
6486cf6ee76SBrian Somers         if (algorithm[f]->Required(fp)) {
6496cf6ee76SBrian Somers           log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
6506cf6ee76SBrian Somers                      fp->link->name, protoname(algorithm[f]->id));
6516cf6ee76SBrian Somers           fsm_Close(&fp->link->lcp.fsm);
6526cf6ee76SBrian Somers         }
653af57ed9fSAtsushi Murai         break;
654af57ed9fSAtsushi Murai       }
655af57ed9fSAtsushi Murai     }
656af57ed9fSAtsushi Murai   }
6570053cc58SBrian Somers 
658e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
659ff360cc9SBrian Somers     fsm_opt_normalise(dec);
660ff360cc9SBrian Somers     if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
66103036ec7SBrian Somers       if (ccp->in.state == NULL) {
66203036ec7SBrian Somers         ccp->his_proto = -1;
66303036ec7SBrian Somers         ccp->in.algorithm = -1;
664247ab36dSBrian Somers       }
6651ae349f5Scvs2svn     }
6660053cc58SBrian Somers   }
667af57ed9fSAtsushi Murai }
668af57ed9fSAtsushi Murai 
6695d9e6103SBrian Somers extern struct mbuf *
6705d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
671af57ed9fSAtsushi Murai {
6727308ec68SBrian Somers   /* Got PROTO_CCP from link */
67326af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
674455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
6755d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
676af57ed9fSAtsushi Murai   else {
677641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
678dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
6795d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
68026af0ae9SBrian Somers     m_freem(bp);
681af57ed9fSAtsushi Murai   }
6825d9e6103SBrian Somers   return NULL;
683af57ed9fSAtsushi Murai }
6840053cc58SBrian Somers 
685503a7782SBrian Somers static void
686503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
6870053cc58SBrian Somers {
6887308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
689f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
690f4768038SBrian Somers 
691f4768038SBrian Somers   if (ccp->reset_sent != -1) {
692f4768038SBrian Somers     if (id != ccp->reset_sent) {
693a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
694d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
69598baf7c8SBrian Somers       return;
69698baf7c8SBrian Somers     }
69798baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
698f4768038SBrian Somers   } else if (id == ccp->last_reset)
699dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
700d47dceb8SBrian Somers                fp->link->name);
70198baf7c8SBrian Somers   else {
702a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
703d47dceb8SBrian Somers                fp->link->name, id);
70498baf7c8SBrian Somers     return;
70598baf7c8SBrian Somers   }
70698baf7c8SBrian Somers 
707f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
708f4768038SBrian Somers   ccp->reset_sent = -1;
70903036ec7SBrian Somers   if (ccp->in.state != NULL)
71003036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
7110053cc58SBrian Somers }
7120053cc58SBrian Somers 
7135d9e6103SBrian Somers static struct mbuf *
714057f1760SBrian Somers ccp_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp,
7155d9e6103SBrian Somers               int pri, u_short *proto)
7160053cc58SBrian Somers {
7176cf6ee76SBrian Somers   if (PROTO_COMPRESSIBLE(*proto)) {
7186cf6ee76SBrian Somers     if (l->ccp.fsm.state != ST_OPENED) {
7196cf6ee76SBrian Somers       if (ccp_Required(&l->ccp)) {
7206cf6ee76SBrian Somers         /* The NCP layer shouldn't have let this happen ! */
7216cf6ee76SBrian Somers         log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
7226cf6ee76SBrian Somers                    " required CCP layer\n", l->name);
7236cf6ee76SBrian Somers         m_freem(bp);
7246cf6ee76SBrian Somers         bp = NULL;
7256cf6ee76SBrian Somers       }
7266cf6ee76SBrian Somers     } else if (l->ccp.out.state != NULL) {
727411675baSBrian Somers       bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
7285d9e6103SBrian Somers              (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
729411675baSBrian Somers       switch (*proto) {
730411675baSBrian Somers         case PROTO_ICOMPD:
73126af0ae9SBrian Somers           m_settype(bp, MB_ICOMPDOUT);
732411675baSBrian Somers           break;
733411675baSBrian Somers         case PROTO_COMPD:
73426af0ae9SBrian Somers           m_settype(bp, MB_COMPDOUT);
735411675baSBrian Somers           break;
736411675baSBrian Somers       }
737411675baSBrian Somers     }
7386cf6ee76SBrian Somers   }
7395d9e6103SBrian Somers 
7405d9e6103SBrian Somers   return bp;
7410053cc58SBrian Somers }
7420053cc58SBrian Somers 
7435d9e6103SBrian Somers static struct mbuf *
744057f1760SBrian Somers ccp_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp,
745057f1760SBrian Somers 	      u_short *proto)
7460053cc58SBrian Somers {
747ee6c193fSBrian Somers   /*
748ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
749ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
750ee6c193fSBrian Somers    */
7515d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
752ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
7537308ec68SBrian Somers       /* Decompress incoming data */
7545d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
75598baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
756411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
757411675baSBrian Somers                    MB_CCPOUT);
758411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
759411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
7605d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
761411675baSBrian Somers         switch (*proto) {
762411675baSBrian Somers           case PROTO_ICOMPD:
76326af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
764411675baSBrian Somers             break;
765411675baSBrian Somers           case PROTO_COMPD:
76626af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
767411675baSBrian Somers             break;
768411675baSBrian Somers         }
769411675baSBrian Somers         return bp;
770411675baSBrian Somers       }
77126af0ae9SBrian Somers       m_freem(bp);
772ee6c193fSBrian Somers       bp = NULL;
7736815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
774ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
7755d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
7765d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
777e0efa796SBrian Somers     }
7780053cc58SBrian Somers   }
7790053cc58SBrian Somers 
780ee6c193fSBrian Somers   return bp;
7811ae349f5Scvs2svn }
782ed32233cSBrian Somers 
783ed32233cSBrian Somers u_short
784ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
7850053cc58SBrian Somers {
786ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
787ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
7880053cc58SBrian Somers }
7891df0a3b9SBrian Somers 
79006337856SBrian Somers int
7911df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
7921df0a3b9SBrian Somers {
7931df0a3b9SBrian Somers   int f;
7941df0a3b9SBrian Somers 
7951df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
79606337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
7971df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
79806337856SBrian Somers       return 1;
79906337856SBrian Somers     }
8001df0a3b9SBrian Somers 
80106337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
80206337856SBrian Somers 
80306337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
80406337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
80506337856SBrian Somers       return 1;
80606337856SBrian Somers 
80706337856SBrian Somers   return 0;				/* No CCP at all */
8081df0a3b9SBrian Somers }
8095d9e6103SBrian Somers 
8107f89db65SBrian Somers int
811057f1760SBrian Somers ccp_DefaultUsable(struct fsm *fp __unused)
8127f89db65SBrian Somers {
8137f89db65SBrian Somers   return 1;
8147f89db65SBrian Somers }
8157f89db65SBrian Somers 
8166cf6ee76SBrian Somers int
817057f1760SBrian Somers ccp_DefaultRequired(struct fsm *fp __unused)
8186cf6ee76SBrian Somers {
8196cf6ee76SBrian Somers   return 0;
8206cf6ee76SBrian Somers }
8216cf6ee76SBrian Somers 
8225d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
823