xref: /freebsd/usr.sbin/ppp/ccp.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
165309e5cSBrian Somers /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro 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  */
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 *
protoname(int proto)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
ccp_ReportStatus(struct cmdargs const * arg)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
ccp_SetupCallbacks(struct ccp * ccp)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
ccp_Init(struct ccp * ccp,struct bundle * bundle,struct link * l,const struct fsm_parent * parent)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
ccp_Setup(struct ccp * ccp)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
ccp_Required(struct ccp * ccp)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
ccp_MTUOverhead(struct ccp * ccp)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
CcpInitRestartCounter(struct fsm * fp,int what)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
CcpSendConfigReq(struct fsm * fp)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) {
3695d604c11SBrian Somers         if ((*o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt))) == NULL) {
3705d604c11SBrian Somers 	  log_Printf(LogERROR, "%s: Not enough memory for CCP REQ !\n",
3715d604c11SBrian Somers 		     fp->link->name);
3725d604c11SBrian Somers 	  break;
3735d604c11SBrian Somers 	}
374ff360cc9SBrian Somers         (*o)->val.hdr.id = algorithm[f]->id;
375ff360cc9SBrian Somers         (*o)->val.hdr.len = 2;
37603036ec7SBrian Somers         (*o)->next = NULL;
37703036ec7SBrian Somers         (*o)->algorithm = f;
3788fb5ef5aSBrian Somers         (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
379af57ed9fSAtsushi Murai       }
3801ae349f5Scvs2svn 
381ff360cc9SBrian Somers       if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
382dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
38330c2f2ffSBrian Somers         break;
38430c2f2ffSBrian Somers       }
385ff360cc9SBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.hdr.len);
386ff360cc9SBrian Somers       cp += (*o)->val.hdr.len;
38703036ec7SBrian Somers 
388ff360cc9SBrian Somers       ccp->my_proto = (*o)->val.hdr.id;
38903036ec7SBrian Somers       ccp->out.algorithm = f;
39003036ec7SBrian Somers 
39103036ec7SBrian Somers       if (alloc)
39203036ec7SBrian Somers         o = &(*o)->next;
3931ae349f5Scvs2svn     }
3942267893fSBrian Somers 
395411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
396af57ed9fSAtsushi Murai }
397af57ed9fSAtsushi Murai 
398af57ed9fSAtsushi Murai void
ccp_SendResetReq(struct fsm * fp)399dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
400af57ed9fSAtsushi Murai {
4017308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
402aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
4032267893fSBrian Somers 
40483d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
40583d1af55SBrian Somers   ccp->last_reset = -1;
406411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
407af57ed9fSAtsushi Murai }
408af57ed9fSAtsushi Murai 
409af57ed9fSAtsushi Murai static void
CcpSentTerminateReq(struct fsm * fp __unused)410057f1760SBrian Somers CcpSentTerminateReq(struct fsm *fp __unused)
411af57ed9fSAtsushi Murai {
4127308ec68SBrian Somers   /* Term REQ just sent by FSM */
413af57ed9fSAtsushi Murai }
414af57ed9fSAtsushi Murai 
415af57ed9fSAtsushi Murai static void
CcpSendTerminateAck(struct fsm * fp,u_char id)4162267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
417af57ed9fSAtsushi Murai {
4187308ec68SBrian Somers   /* Send Term ACK please */
419411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
420af57ed9fSAtsushi Murai }
421af57ed9fSAtsushi Murai 
4226cf6ee76SBrian Somers static int
CcpRecvResetReq(struct fsm * fp)423944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
424af57ed9fSAtsushi Murai {
4257308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
426aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
4276cf6ee76SBrian Somers   if (ccp->out.state == NULL)
4286cf6ee76SBrian Somers     return 1;
4296cf6ee76SBrian Somers   return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
430af57ed9fSAtsushi Murai }
431af57ed9fSAtsushi Murai 
432af57ed9fSAtsushi Murai static void
CcpLayerStart(struct fsm * fp)433944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
434af57ed9fSAtsushi Murai {
4357308ec68SBrian Somers   /* We're about to start up ! */
436479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
437479508cfSBrian Somers 
4383a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
439479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
440af57ed9fSAtsushi Murai }
441af57ed9fSAtsushi Murai 
442af57ed9fSAtsushi Murai static void
CcpLayerDown(struct fsm * fp)443897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
444af57ed9fSAtsushi Murai {
445897f9429SBrian Somers   /* About to come down */
446aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
447ba081e43SBrian Somers   struct ccp_opt *next;
448ba081e43SBrian Somers 
4493a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
45003036ec7SBrian Somers   if (ccp->in.state != NULL) {
45103036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
45203036ec7SBrian Somers     ccp->in.state = NULL;
4538d9b9867SBrian Somers     ccp->in.algorithm = -1;
4547308ec68SBrian Somers   }
45503036ec7SBrian Somers   if (ccp->out.state != NULL) {
45603036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
45703036ec7SBrian Somers     ccp->out.state = NULL;
4588d9b9867SBrian Somers     ccp->out.algorithm = -1;
4597308ec68SBrian Somers   }
4608d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
461ba081e43SBrian Somers 
462ba081e43SBrian Somers   while (ccp->out.opt) {
463ba081e43SBrian Somers     next = ccp->out.opt->next;
464ba081e43SBrian Somers     free(ccp->out.opt);
465ba081e43SBrian Somers     ccp->out.opt = next;
466ba081e43SBrian Somers   }
467897f9429SBrian Somers   ccp_Setup(ccp);
468af57ed9fSAtsushi Murai }
469af57ed9fSAtsushi Murai 
470af57ed9fSAtsushi Murai static void
CcpLayerFinish(struct fsm * fp)471897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
472af57ed9fSAtsushi Murai {
473897f9429SBrian Somers   /* We're now down */
474e1e8b15eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
475e1e8b15eSBrian Somers   struct ccp_opt *next;
476e1e8b15eSBrian Somers 
4773a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
478e1e8b15eSBrian Somers 
479e1e8b15eSBrian Somers   /*
480e1e8b15eSBrian Somers    * Nuke options that may be left over from sending a REQ but never
481e1e8b15eSBrian Somers    * coming up.
482e1e8b15eSBrian Somers    */
483e1e8b15eSBrian Somers   while (ccp->out.opt) {
484e1e8b15eSBrian Somers     next = ccp->out.opt->next;
485e1e8b15eSBrian Somers     free(ccp->out.opt);
486e1e8b15eSBrian Somers     ccp->out.opt = next;
487e1e8b15eSBrian Somers   }
4886cf6ee76SBrian Somers 
4896cf6ee76SBrian Somers   if (ccp_Required(ccp)) {
4906cf6ee76SBrian Somers     if (fp->link->lcp.fsm.state == ST_OPENED)
4916cf6ee76SBrian Somers       log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
4926cf6ee76SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
4936cf6ee76SBrian Somers   }
494af57ed9fSAtsushi Murai }
495af57ed9fSAtsushi Murai 
4963377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
4976f384573SBrian Somers static int
CcpLayerUp(struct fsm * fp)498944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
499af57ed9fSAtsushi Murai {
5007308ec68SBrian Somers   /* We're now up */
501aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
502e1e8b15eSBrian Somers   struct ccp_opt **o;
503057f1760SBrian Somers   unsigned f, fail;
5046301d506SBrian Somers 
5056301d506SBrian Somers   for (f = fail = 0; f < NALGORITHMS; f++)
5066301d506SBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
5076301d506SBrian Somers         (*algorithm[f]->Required)(&ccp->fsm) &&
508057f1760SBrian Somers         (ccp->in.algorithm != (int)f || ccp->out.algorithm != (int)f)) {
5096301d506SBrian Somers       /* Blow it all away - we haven't negotiated a required algorithm */
5106301d506SBrian Somers       log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
5116301d506SBrian Somers                  fp->link->name, protoname(algorithm[f]->id));
5126301d506SBrian Somers       fail = 1;
5136301d506SBrian Somers     }
5146301d506SBrian Somers 
5156301d506SBrian Somers   if (fail) {
5166301d506SBrian Somers     ccp->his_proto = ccp->my_proto = -1;
5176301d506SBrian Somers     fsm_Close(fp);
5186301d506SBrian Somers     fsm_Close(&fp->link->lcp.fsm);
5196301d506SBrian Somers     return 0;
5206301d506SBrian Somers   }
521479508cfSBrian Somers 
5223a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
523479508cfSBrian Somers 
52403036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
525057f1760SBrian Somers       ccp->in.algorithm < (int)NALGORITHMS) {
5268fb5ef5aSBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
5278fb5ef5aSBrian Somers       (fp->bundle, &ccp->in.opt);
52803036ec7SBrian Somers     if (ccp->in.state == NULL) {
529dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
530d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
53183d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
532dd7e2610SBrian Somers       fsm_Close(fp);
533479508cfSBrian Somers       return 0;
53479d1bdaeSBrian Somers     }
535af57ed9fSAtsushi Murai   }
536af57ed9fSAtsushi Murai 
537e1e8b15eSBrian Somers   o = &ccp->out.opt;
538057f1760SBrian Somers   if (ccp->out.algorithm > 0)
539057f1760SBrian Somers     for (f = 0; f < (unsigned)ccp->out.algorithm; f++)
540e1e8b15eSBrian Somers       if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
541e1e8b15eSBrian Somers 	o = &(*o)->next;
542e1e8b15eSBrian Somers 
54303036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
544057f1760SBrian Somers       ccp->out.algorithm < (int)NALGORITHMS) {
5458fb5ef5aSBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
5468fb5ef5aSBrian Somers       (fp->bundle, &(*o)->val);
54703036ec7SBrian Somers     if (ccp->out.state == NULL) {
548dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
549d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
55083d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
551dd7e2610SBrian Somers       fsm_Close(fp);
552479508cfSBrian Somers       return 0;
553247ab36dSBrian Somers     }
554af57ed9fSAtsushi Murai   }
555af57ed9fSAtsushi Murai 
556479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
557479508cfSBrian Somers 
558dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
559d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
56083d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
561479508cfSBrian Somers 
5626f384573SBrian Somers   return 1;
563af57ed9fSAtsushi Murai }
564af57ed9fSAtsushi Murai 
565af57ed9fSAtsushi Murai static void
CcpDecodeConfig(struct fsm * fp,u_char * cp,u_char * end,int mode_type,struct fsm_decode * dec)566ff360cc9SBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
56730c2f2ffSBrian Somers                 struct fsm_decode *dec)
568af57ed9fSAtsushi Murai {
5697308ec68SBrian Somers   /* Deal with incoming data */
570aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
571ff360cc9SBrian Somers   int f;
572ff360cc9SBrian Somers   const char *disp;
573ff360cc9SBrian Somers   struct fsm_opt *opt;
574af57ed9fSAtsushi Murai 
57531516407SBrian Somers   if (mode_type == MODE_REQ)
57631516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
57731516407SBrian Somers 
578057f1760SBrian Somers   while (end >= cp + sizeof(opt->hdr)) {
579ff360cc9SBrian Somers     if ((opt = fsm_readopt(&cp)) == NULL)
580d47dceb8SBrian Somers       break;
581af57ed9fSAtsushi Murai 
5820053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
583ff360cc9SBrian Somers       if (algorithm[f]->id == opt->hdr.id)
5840053cc58SBrian Somers         break;
585af57ed9fSAtsushi Murai 
586ff360cc9SBrian Somers     disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
587ff360cc9SBrian Somers     if (disp == NULL)
588ff360cc9SBrian Somers       disp = "";
58903036ec7SBrian Somers 
590ff360cc9SBrian Somers     log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
591ff360cc9SBrian Somers                opt->hdr.len, disp);
59203036ec7SBrian Somers 
5930053cc58SBrian Somers     if (f == -1) {
5940053cc58SBrian Somers       /* Don't understand that :-( */
5950053cc58SBrian Somers       if (mode_type == MODE_REQ) {
596ff360cc9SBrian Somers         ccp->my_reject |= (1 << opt->hdr.id);
597ff360cc9SBrian Somers         fsm_rej(dec, opt);
5980053cc58SBrian Somers       }
5990053cc58SBrian Somers     } else {
60003036ec7SBrian Somers       struct ccp_opt *o;
6010053cc58SBrian Somers 
6029780ef31SBrian Somers       switch (mode_type) {
603af57ed9fSAtsushi Murai       case MODE_REQ:
6041342caedSBrian Somers         if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
6057f89db65SBrian Somers             (*algorithm[f]->Usable)(fp) &&
6061342caedSBrian Somers             ccp->in.algorithm == -1) {
607ff360cc9SBrian Somers           memcpy(&ccp->in.opt, opt, opt->hdr.len);
6088fb5ef5aSBrian Somers           switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
6090053cc58SBrian Somers           case MODE_REJ:
610ff360cc9SBrian Somers             fsm_rej(dec, &ccp->in.opt);
6110053cc58SBrian Somers             break;
6120053cc58SBrian Somers           case MODE_NAK:
613ff360cc9SBrian Somers             fsm_nak(dec, &ccp->in.opt);
6140053cc58SBrian Somers             break;
6150053cc58SBrian Somers           case MODE_ACK:
616ff360cc9SBrian Somers             fsm_ack(dec, &ccp->in.opt);
617ff360cc9SBrian Somers             ccp->his_proto = opt->hdr.id;
618057f1760SBrian Somers             ccp->in.algorithm = (int)f;		/* This one'll do :-) */
6190053cc58SBrian Somers             break;
6200053cc58SBrian Somers           }
621af57ed9fSAtsushi Murai         } else {
622ff360cc9SBrian Somers           fsm_rej(dec, opt);
623af57ed9fSAtsushi Murai         }
624af57ed9fSAtsushi Murai         break;
625af57ed9fSAtsushi Murai       case MODE_NAK:
62603036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
627ff360cc9SBrian Somers           if (o->val.hdr.id == opt->hdr.id)
62803036ec7SBrian Somers             break;
62903036ec7SBrian Somers         if (o == NULL)
6309b996792SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
6319b996792SBrian Somers                      " option\n", fp->link->name);
6320053cc58SBrian Somers         else {
633ff360cc9SBrian Somers           memcpy(&o->val, opt, opt->hdr.len);
6348fb5ef5aSBrian Somers           if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
6358fb5ef5aSBrian Somers               MODE_ACK)
63683d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
6371ae349f5Scvs2svn           else {
638ff360cc9SBrian Somers             ccp->his_reject |= (1 << opt->hdr.id);
63983d1af55SBrian Somers             ccp->my_proto = -1;
6406cf6ee76SBrian Somers             if (algorithm[f]->Required(fp)) {
6416cf6ee76SBrian Somers               log_Printf(LogWARN, "%s: Cannot understand peers (required)"
6426cf6ee76SBrian Somers                          " %s negotiation\n", fp->link->name,
6436cf6ee76SBrian Somers                          protoname(algorithm[f]->id));
6446cf6ee76SBrian Somers               fsm_Close(&fp->link->lcp.fsm);
6456cf6ee76SBrian Somers             }
6461ae349f5Scvs2svn           }
6470053cc58SBrian Somers         }
6480053cc58SBrian Somers         break;
649af57ed9fSAtsushi Murai       case MODE_REJ:
650ff360cc9SBrian Somers         ccp->his_reject |= (1 << opt->hdr.id);
65183d1af55SBrian Somers         ccp->my_proto = -1;
6526cf6ee76SBrian Somers         if (algorithm[f]->Required(fp)) {
6536cf6ee76SBrian Somers           log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
6546cf6ee76SBrian Somers                      fp->link->name, protoname(algorithm[f]->id));
6556cf6ee76SBrian Somers           fsm_Close(&fp->link->lcp.fsm);
6566cf6ee76SBrian Somers         }
657af57ed9fSAtsushi Murai         break;
658af57ed9fSAtsushi Murai       }
659af57ed9fSAtsushi Murai     }
660af57ed9fSAtsushi Murai   }
6610053cc58SBrian Somers 
662e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
663ff360cc9SBrian Somers     fsm_opt_normalise(dec);
664ff360cc9SBrian Somers     if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
66503036ec7SBrian Somers       if (ccp->in.state == NULL) {
66603036ec7SBrian Somers         ccp->his_proto = -1;
66703036ec7SBrian Somers         ccp->in.algorithm = -1;
668247ab36dSBrian Somers       }
6691ae349f5Scvs2svn     }
6700053cc58SBrian Somers   }
671af57ed9fSAtsushi Murai }
672af57ed9fSAtsushi Murai 
6735d9e6103SBrian Somers extern struct mbuf *
ccp_Input(struct bundle * bundle,struct link * l,struct mbuf * bp)6745d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
675af57ed9fSAtsushi Murai {
6767308ec68SBrian Somers   /* Got PROTO_CCP from link */
67726af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
678455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
6795d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
680af57ed9fSAtsushi Murai   else {
681641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
682dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
6835d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
68426af0ae9SBrian Somers     m_freem(bp);
685af57ed9fSAtsushi Murai   }
6865d9e6103SBrian Somers   return NULL;
687af57ed9fSAtsushi Murai }
6880053cc58SBrian Somers 
689503a7782SBrian Somers static void
CcpRecvResetAck(struct fsm * fp,u_char id)690503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
6910053cc58SBrian Somers {
6927308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
693f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
694f4768038SBrian Somers 
695f4768038SBrian Somers   if (ccp->reset_sent != -1) {
696f4768038SBrian Somers     if (id != ccp->reset_sent) {
697a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
698d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
69998baf7c8SBrian Somers       return;
70098baf7c8SBrian Somers     }
70198baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
702f4768038SBrian Somers   } else if (id == ccp->last_reset)
703dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
704d47dceb8SBrian Somers                fp->link->name);
70598baf7c8SBrian Somers   else {
706a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
707d47dceb8SBrian Somers                fp->link->name, id);
70898baf7c8SBrian Somers     return;
70998baf7c8SBrian Somers   }
71098baf7c8SBrian Somers 
711f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
712f4768038SBrian Somers   ccp->reset_sent = -1;
71303036ec7SBrian Somers   if (ccp->in.state != NULL)
71403036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
7150053cc58SBrian Somers }
7160053cc58SBrian Somers 
7175d9e6103SBrian Somers static struct mbuf *
ccp_LayerPush(struct bundle * b __unused,struct link * l,struct mbuf * bp,int pri,u_short * proto)718057f1760SBrian Somers ccp_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp,
7195d9e6103SBrian Somers               int pri, u_short *proto)
7200053cc58SBrian Somers {
7216cf6ee76SBrian Somers   if (PROTO_COMPRESSIBLE(*proto)) {
7226cf6ee76SBrian Somers     if (l->ccp.fsm.state != ST_OPENED) {
7236cf6ee76SBrian Somers       if (ccp_Required(&l->ccp)) {
7246cf6ee76SBrian Somers         /* The NCP layer shouldn't have let this happen ! */
7256cf6ee76SBrian Somers         log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
7266cf6ee76SBrian Somers                    " required CCP layer\n", l->name);
7276cf6ee76SBrian Somers         m_freem(bp);
7286cf6ee76SBrian Somers         bp = NULL;
7296cf6ee76SBrian Somers       }
7306cf6ee76SBrian Somers     } else if (l->ccp.out.state != NULL) {
731411675baSBrian Somers       bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
7325d9e6103SBrian Somers              (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
733411675baSBrian Somers       switch (*proto) {
734411675baSBrian Somers         case PROTO_ICOMPD:
73526af0ae9SBrian Somers           m_settype(bp, MB_ICOMPDOUT);
736411675baSBrian Somers           break;
737411675baSBrian Somers         case PROTO_COMPD:
73826af0ae9SBrian Somers           m_settype(bp, MB_COMPDOUT);
739411675baSBrian Somers           break;
740411675baSBrian Somers       }
741411675baSBrian Somers     }
7426cf6ee76SBrian Somers   }
7435d9e6103SBrian Somers 
7445d9e6103SBrian Somers   return bp;
7450053cc58SBrian Somers }
7460053cc58SBrian Somers 
7475d9e6103SBrian Somers static struct mbuf *
ccp_LayerPull(struct bundle * b __unused,struct link * l,struct mbuf * bp,u_short * proto)748057f1760SBrian Somers ccp_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp,
749057f1760SBrian Somers 	      u_short *proto)
7500053cc58SBrian Somers {
751ee6c193fSBrian Somers   /*
752ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
753ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
754ee6c193fSBrian Somers    */
7555d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
756ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
7577308ec68SBrian Somers       /* Decompress incoming data */
7585d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
75998baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
760411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
761411675baSBrian Somers                    MB_CCPOUT);
762411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
763411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
7645d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
765411675baSBrian Somers         switch (*proto) {
766411675baSBrian Somers           case PROTO_ICOMPD:
76726af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
768411675baSBrian Somers             break;
769411675baSBrian Somers           case PROTO_COMPD:
77026af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
771411675baSBrian Somers             break;
772411675baSBrian Somers         }
773411675baSBrian Somers         return bp;
774411675baSBrian Somers       }
77526af0ae9SBrian Somers       m_freem(bp);
776ee6c193fSBrian Somers       bp = NULL;
7776815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
778ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
7795d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
7805d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
781e0efa796SBrian Somers     }
7820053cc58SBrian Somers   }
7830053cc58SBrian Somers 
784ee6c193fSBrian Somers   return bp;
7851ae349f5Scvs2svn }
786ed32233cSBrian Somers 
787ed32233cSBrian Somers u_short
ccp_Proto(struct ccp * ccp)788ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
7890053cc58SBrian Somers {
790ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
791ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
7920053cc58SBrian Somers }
7931df0a3b9SBrian Somers 
79406337856SBrian Somers int
ccp_SetOpenMode(struct ccp * ccp)7951df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
7961df0a3b9SBrian Somers {
7971df0a3b9SBrian Somers   int f;
7981df0a3b9SBrian Somers 
7991df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
80006337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
8011df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
80206337856SBrian Somers       return 1;
80306337856SBrian Somers     }
8041df0a3b9SBrian Somers 
80506337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
80606337856SBrian Somers 
80706337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
80806337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
80906337856SBrian Somers       return 1;
81006337856SBrian Somers 
81106337856SBrian Somers   return 0;				/* No CCP at all */
8121df0a3b9SBrian Somers }
8135d9e6103SBrian Somers 
8147f89db65SBrian Somers int
ccp_DefaultUsable(struct fsm * fp __unused)815057f1760SBrian Somers ccp_DefaultUsable(struct fsm *fp __unused)
8167f89db65SBrian Somers {
8177f89db65SBrian Somers   return 1;
8187f89db65SBrian Somers }
8197f89db65SBrian Somers 
8206cf6ee76SBrian Somers int
ccp_DefaultRequired(struct fsm * fp __unused)821057f1760SBrian Somers ccp_DefaultRequired(struct fsm *fp __unused)
8226cf6ee76SBrian Somers {
8236cf6ee76SBrian Somers   return 0;
8246cf6ee76SBrian Somers }
8256cf6ee76SBrian Somers 
8265d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
827