xref: /freebsd/usr.sbin/ppp/ccp.c (revision e1e8b15e7a3c90a2100e4847cc84dfda8458327b)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *	   PPP Compression Control Protocol (CCP) Module
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  * Redistribution and use in source and binary forms are permitted
9af57ed9fSAtsushi Murai  * provided that the above copyright notice and this paragraph are
10af57ed9fSAtsushi Murai  * duplicated in all such forms and that any documentation,
11af57ed9fSAtsushi Murai  * advertising materials, and other materials related to such
12af57ed9fSAtsushi Murai  * distribution and use acknowledge that the software was developed
13af57ed9fSAtsushi Murai  * by the Internet Initiative Japan, Inc.  The name of the
14af57ed9fSAtsushi Murai  * IIJ may not be used to endorse or promote products derived
15af57ed9fSAtsushi Murai  * from this software without specific prior written permission.
16af57ed9fSAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17af57ed9fSAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18af57ed9fSAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19af57ed9fSAtsushi Murai  *
2097d92980SPeter Wemm  * $FreeBSD$
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
23af57ed9fSAtsushi Murai  *		o Support other compression protocols
24af57ed9fSAtsushi Murai  */
25972a1bcfSBrian Somers #include <sys/param.h>
2675240ed1SBrian Somers #include <netinet/in.h>
27eaa4df37SBrian Somers #include <netinet/in_systm.h>
28eaa4df37SBrian Somers #include <netinet/ip.h>
291fa665f5SBrian Somers #include <sys/un.h>
3075240ed1SBrian Somers 
3175240ed1SBrian Somers #include <stdio.h>
3203036ec7SBrian Somers #include <stdlib.h>
33eb6e5e05SBrian Somers #include <string.h>	/* memcpy() on some archs */
3485b542cfSBrian Somers #include <termios.h>
3575240ed1SBrian Somers 
365d9e6103SBrian Somers #include "layer.h"
37c9e11a11SBrian Somers #include "defs.h"
38b6e82f33SBrian Somers #include "command.h"
3975240ed1SBrian Somers #include "mbuf.h"
4075240ed1SBrian Somers #include "log.h"
4175240ed1SBrian Somers #include "timer.h"
42af57ed9fSAtsushi Murai #include "fsm.h"
435d9e6103SBrian Somers #include "proto.h"
44ed6a16c1SPoul-Henning Kamp #include "pred.h"
450053cc58SBrian Somers #include "deflate.h"
465828db6dSBrian Somers #include "throughput.h"
475828db6dSBrian Somers #include "iplist.h"
48eaa4df37SBrian Somers #include "slcompress.h"
495a72b6edSBrian Somers #include "lqr.h"
505a72b6edSBrian Somers #include "hdlc.h"
511038894eSBrian Somers #include "lcp.h"
521038894eSBrian Somers #include "ccp.h"
535828db6dSBrian Somers #include "ipcp.h"
545ca5389aSBrian Somers #include "filter.h"
5585b542cfSBrian Somers #include "descriptor.h"
5685b542cfSBrian Somers #include "prompt.h"
57503a7782SBrian Somers #include "link.h"
583b0f8d2eSBrian Somers #include "mp.h"
59ed32233cSBrian Somers #include "async.h"
60ed32233cSBrian Somers #include "physical.h"
61972a1bcfSBrian Somers #ifndef NORADIUS
62972a1bcfSBrian Somers #include "radius.h"
63972a1bcfSBrian Somers #endif
64a8d604abSBrian Somers #ifdef HAVE_DES
65a8d604abSBrian Somers #include "mppe.h"
66a8d604abSBrian Somers #endif
673b0f8d2eSBrian Somers #include "bundle.h"
68af57ed9fSAtsushi Murai 
69927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
702267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
712267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
7230c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
7330c2f2ffSBrian Somers                             struct fsm_decode *);
74927145beSBrian Somers static void CcpLayerStart(struct fsm *);
75927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
766f384573SBrian Somers static int CcpLayerUp(struct fsm *);
77927145beSBrian Somers static void CcpLayerDown(struct fsm *);
78479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int);
79503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
80503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
81af57ed9fSAtsushi Murai 
8283d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
83af57ed9fSAtsushi Murai   CcpLayerUp,
84af57ed9fSAtsushi Murai   CcpLayerDown,
85af57ed9fSAtsushi Murai   CcpLayerStart,
86af57ed9fSAtsushi Murai   CcpLayerFinish,
87af57ed9fSAtsushi Murai   CcpInitRestartCounter,
88af57ed9fSAtsushi Murai   CcpSendConfigReq,
892267893fSBrian Somers   CcpSentTerminateReq,
90af57ed9fSAtsushi Murai   CcpSendTerminateAck,
91af57ed9fSAtsushi Murai   CcpDecodeConfig,
92503a7782SBrian Somers   CcpRecvResetReq,
93503a7782SBrian Somers   CcpRecvResetAck
94af57ed9fSAtsushi Murai };
95af57ed9fSAtsushi Murai 
96182c898aSBrian Somers static const char * const ccp_TimerNames[] =
976f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
986f384573SBrian Somers 
99d6d3eeabSBrian Somers static const char *
100d6d3eeabSBrian Somers protoname(int proto)
101d6d3eeabSBrian Somers {
102182c898aSBrian Somers   static char const * const cftypes[] = {
103d6d3eeabSBrian Somers     /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
1049e836af5SBrian Somers     "OUI",		/* 0: OUI */
1059e836af5SBrian Somers     "PRED1",		/* 1: Predictor type 1 */
1069e836af5SBrian Somers     "PRED2",		/* 2: Predictor type 2 */
1079e836af5SBrian Somers     "PUDDLE",		/* 3: Puddle Jumber */
108d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
109d6d3eeabSBrian Somers     NULL, NULL, NULL, NULL, NULL, NULL,
1109e836af5SBrian Somers     "HWPPC",		/* 16: Hewlett-Packard PPC */
1114bc84b8cSBrian Somers     "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
112a8d604abSBrian Somers     "MPPE",		/* 18: Microsoft PPC (rfc2118) and */
113a8d604abSBrian Somers 			/*     Microsoft PPE (draft-ietf-pppext-mppe) */
1144bc84b8cSBrian Somers     "GAND",		/* 19: Gandalf FZA (rfc1993) */
115b6e82f33SBrian Somers     "V42BIS",		/* 20: ARG->DATA.42bis compression */
1160053cc58SBrian Somers     "BSD",		/* 21: BSD LZW Compress */
117d6d3eeabSBrian Somers     NULL,
1184bc84b8cSBrian Somers     "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1194bc84b8cSBrian Somers     "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
1201342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1214bc84b8cSBrian Somers     "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1224bc84b8cSBrian Somers     "DEFLATE",		/* 26: Deflate (rfc1979) */
123af57ed9fSAtsushi Murai   };
124af57ed9fSAtsushi Murai 
125d6d3eeabSBrian Somers   if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes ||
126d6d3eeabSBrian Somers       cftypes[proto] == NULL)
127d6d3eeabSBrian Somers     return HexStr(proto, NULL, 0);
1289e836af5SBrian Somers 
1290053cc58SBrian Somers   return cftypes[proto];
1300053cc58SBrian Somers }
1310053cc58SBrian Somers 
1324bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
133182c898aSBrian Somers static const struct ccp_algorithm * const algorithm[] = {
1344bc84b8cSBrian Somers   &DeflateAlgorithm,
1350053cc58SBrian Somers   &Pred1Algorithm,
1364bc84b8cSBrian Somers   &PppdDeflateAlgorithm
137a8d604abSBrian Somers #ifdef HAVE_DES
138a8d604abSBrian Somers   , &MPPEAlgorithm
139a8d604abSBrian Somers #endif
1400053cc58SBrian Somers };
1410053cc58SBrian Somers 
14270ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1430053cc58SBrian Somers 
144274e766cSBrian Somers int
145503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
146af57ed9fSAtsushi Murai {
147dd0645c5SBrian Somers   struct link *l;
148dd0645c5SBrian Somers   struct ccp *ccp;
149dd0645c5SBrian Somers 
1503a2e4f62SBrian Somers   l = command_ChooseLink(arg);
151dd0645c5SBrian Somers   ccp = &l->ccp;
152503a7782SBrian Somers 
153b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1541e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
1555d9e6103SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
156b6217683SBrian Somers     prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
157503a7782SBrian Somers                   protoname(ccp->my_proto), protoname(ccp->his_proto));
158b6217683SBrian Somers     prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
159503a7782SBrian Somers                   ccp->uncompout, ccp->compout,
160503a7782SBrian Somers                   ccp->compin, ccp->uncompin);
1615d9e6103SBrian Somers   }
162cd9647a1SBrian Somers 
163b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
164479508cfSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
165479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
166479508cfSBrian Somers                 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
167479508cfSBrian Somers                 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
168b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
169b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
170b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1711342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1721342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1731342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1741342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1751342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1761342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
177a8d604abSBrian Somers #ifdef HAVE_DES
178ba6fcad9SBrian Somers   prompt_Printf(arg->prompt, "           MPPE:       %s",
179a8d604abSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
180ba6fcad9SBrian Somers   prompt_Printf(arg->prompt, " (Key Size = %d-bits)\n", ccp->cfg.mppe.keybits);
181a8d604abSBrian Somers #endif
182274e766cSBrian Somers   return 0;
183af57ed9fSAtsushi Murai }
184af57ed9fSAtsushi Murai 
1851ae349f5Scvs2svn void
1866f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
187af57ed9fSAtsushi Murai {
1886f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
1896f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
1906f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
1916f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
192ea661041SBrian Somers }
193ea661041SBrian Somers 
194ea661041SBrian Somers void
1956d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1966d666775SBrian Somers          const struct fsm_parent *parent)
197ea661041SBrian Somers {
1987308ec68SBrian Somers   /* Initialise ourselves */
1993b0f8d2eSBrian Somers 
200479508cfSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
2016f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
202cd9647a1SBrian Somers 
20303036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
20403036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
205479508cfSBrian Somers   ccp->cfg.fsm.timeout = DEF_FSMRETRY;
206479508cfSBrian Somers   ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
207479508cfSBrian Somers   ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
2081342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
2091342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
2101342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
211a8d604abSBrian Somers #ifdef HAVE_DES
212a8d604abSBrian Somers   ccp->cfg.mppe.keybits = 128;
213a8d604abSBrian Somers   ccp->cfg.neg[CCP_NEG_MPPE] = 0;
214a8d604abSBrian Somers #endif
215cd9647a1SBrian Somers 
216503a7782SBrian Somers   ccp_Setup(ccp);
217503a7782SBrian Somers }
218503a7782SBrian Somers 
219503a7782SBrian Somers void
220503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
221503a7782SBrian Somers {
222503a7782SBrian Somers   /* Set ourselves up for a startup */
223503a7782SBrian Somers   ccp->fsm.open_mode = 0;
224503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
225503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
22603036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
22703036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
22803036ec7SBrian Somers   ccp->in.opt.id = -1;
22903036ec7SBrian Somers   ccp->out.opt = NULL;
230503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
231503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
232503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
233af57ed9fSAtsushi Murai }
234af57ed9fSAtsushi Murai 
235af57ed9fSAtsushi Murai static void
236479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what)
237af57ed9fSAtsushi Murai {
2387308ec68SBrian Somers   /* Set fsm timer load */
239cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
240cd9647a1SBrian Somers 
241479508cfSBrian Somers   fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
242479508cfSBrian Somers   switch (what) {
243479508cfSBrian Somers     case FSM_REQ_TIMER:
244479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxreq;
245479508cfSBrian Somers       break;
246479508cfSBrian Somers     case FSM_TRM_TIMER:
247479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxtrm;
248479508cfSBrian Somers       break;
249479508cfSBrian Somers     default:
250479508cfSBrian Somers       fp->restart = 1;
251479508cfSBrian Somers       break;
252479508cfSBrian Somers   }
253af57ed9fSAtsushi Murai }
254af57ed9fSAtsushi Murai 
255af57ed9fSAtsushi Murai static void
256944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
257af57ed9fSAtsushi Murai {
2587308ec68SBrian Somers   /* Send config REQ please */
259aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
26003036ec7SBrian Somers   struct ccp_opt **o;
26130c2f2ffSBrian Somers   u_char *cp, buff[100];
26203036ec7SBrian Somers   int f, alloc;
263af57ed9fSAtsushi Murai 
26430c2f2ffSBrian Somers   cp = buff;
26503036ec7SBrian Somers   o = &ccp->out.opt;
26603036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
26783d1af55SBrian Somers   ccp->my_proto = -1;
26803036ec7SBrian Somers   ccp->out.algorithm = -1;
2690053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
2701342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2711342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
2720053cc58SBrian Somers 
273ba081e43SBrian Somers       if (!alloc)
274ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
275ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
276ba081e43SBrian Somers             break;
277ba081e43SBrian Somers 
278ba081e43SBrian Somers       if (alloc || *o == NULL) {
27903036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
28003036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
28103036ec7SBrian Somers         (*o)->val.len = 2;
28203036ec7SBrian Somers         (*o)->next = NULL;
28303036ec7SBrian Somers         (*o)->algorithm = f;
28403036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
285af57ed9fSAtsushi Murai       }
2861ae349f5Scvs2svn 
28703036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
288dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
28930c2f2ffSBrian Somers         break;
29030c2f2ffSBrian Somers       }
2912267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2922267893fSBrian Somers       cp += (*o)->val.len;
29303036ec7SBrian Somers 
29403036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
29503036ec7SBrian Somers       ccp->out.algorithm = f;
29603036ec7SBrian Somers 
29703036ec7SBrian Somers       if (alloc)
29803036ec7SBrian Somers         o = &(*o)->next;
2991ae349f5Scvs2svn     }
3002267893fSBrian Somers 
301411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
302af57ed9fSAtsushi Murai }
303af57ed9fSAtsushi Murai 
304af57ed9fSAtsushi Murai void
305dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
306af57ed9fSAtsushi Murai {
3077308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
308aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3092267893fSBrian Somers 
31083d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
31183d1af55SBrian Somers   ccp->last_reset = -1;
312411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
313af57ed9fSAtsushi Murai }
314af57ed9fSAtsushi Murai 
315af57ed9fSAtsushi Murai static void
3162267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
317af57ed9fSAtsushi Murai {
3187308ec68SBrian Somers   /* Term REQ just sent by FSM */
319af57ed9fSAtsushi Murai }
320af57ed9fSAtsushi Murai 
321af57ed9fSAtsushi Murai static void
3222267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
323af57ed9fSAtsushi Murai {
3247308ec68SBrian Somers   /* Send Term ACK please */
325411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
326af57ed9fSAtsushi Murai }
327af57ed9fSAtsushi Murai 
328503a7782SBrian Somers static void
329944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
330af57ed9fSAtsushi Murai {
3317308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
332aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
33303036ec7SBrian Somers   if (ccp->out.state != NULL)
33403036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
335af57ed9fSAtsushi Murai }
336af57ed9fSAtsushi Murai 
337af57ed9fSAtsushi Murai static void
338944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
339af57ed9fSAtsushi Murai {
3407308ec68SBrian Somers   /* We're about to start up ! */
341479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
342479508cfSBrian Somers 
3433a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
344479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
345af57ed9fSAtsushi Murai }
346af57ed9fSAtsushi Murai 
347af57ed9fSAtsushi Murai static void
348897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
349af57ed9fSAtsushi Murai {
350897f9429SBrian Somers   /* About to come down */
351aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
352ba081e43SBrian Somers   struct ccp_opt *next;
353ba081e43SBrian Somers 
3543a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
35503036ec7SBrian Somers   if (ccp->in.state != NULL) {
35603036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
35703036ec7SBrian Somers     ccp->in.state = NULL;
3588d9b9867SBrian Somers     ccp->in.algorithm = -1;
3597308ec68SBrian Somers   }
36003036ec7SBrian Somers   if (ccp->out.state != NULL) {
36103036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
36203036ec7SBrian Somers     ccp->out.state = NULL;
3638d9b9867SBrian Somers     ccp->out.algorithm = -1;
3647308ec68SBrian Somers   }
3658d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
366ba081e43SBrian Somers 
367ba081e43SBrian Somers   while (ccp->out.opt) {
368ba081e43SBrian Somers     next = ccp->out.opt->next;
369ba081e43SBrian Somers     free(ccp->out.opt);
370ba081e43SBrian Somers     ccp->out.opt = next;
371ba081e43SBrian Somers   }
372897f9429SBrian Somers   ccp_Setup(ccp);
373af57ed9fSAtsushi Murai }
374af57ed9fSAtsushi Murai 
375af57ed9fSAtsushi Murai static void
376897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
377af57ed9fSAtsushi Murai {
378897f9429SBrian Somers   /* We're now down */
379e1e8b15eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
380e1e8b15eSBrian Somers   struct ccp_opt *next;
381e1e8b15eSBrian Somers 
3823a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
383e1e8b15eSBrian Somers 
384e1e8b15eSBrian Somers   /*
385e1e8b15eSBrian Somers    * Nuke options that may be left over from sending a REQ but never
386e1e8b15eSBrian Somers    * coming up.
387e1e8b15eSBrian Somers    */
388e1e8b15eSBrian Somers   while (ccp->out.opt) {
389e1e8b15eSBrian Somers     next = ccp->out.opt->next;
390e1e8b15eSBrian Somers     free(ccp->out.opt);
391e1e8b15eSBrian Somers     ccp->out.opt = next;
392e1e8b15eSBrian Somers   }
393af57ed9fSAtsushi Murai }
394af57ed9fSAtsushi Murai 
3953377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
3966f384573SBrian Somers static int
397944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
398af57ed9fSAtsushi Murai {
3997308ec68SBrian Somers   /* We're now up */
400aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
401e1e8b15eSBrian Somers   struct ccp_opt **o;
402e1e8b15eSBrian Somers   int f;
403479508cfSBrian Somers 
4043a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
405479508cfSBrian Somers 
40603036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
40703036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
40803036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
40903036ec7SBrian Somers     if (ccp->in.state == NULL) {
410dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
411d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
41283d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
413dd7e2610SBrian Somers       fsm_Close(fp);
414479508cfSBrian Somers       return 0;
41579d1bdaeSBrian Somers     }
416af57ed9fSAtsushi Murai   }
417af57ed9fSAtsushi Murai 
418e1e8b15eSBrian Somers   o = &ccp->out.opt;
419e1e8b15eSBrian Somers   for (f = 0; f < ccp->out.algorithm; f++)
420e1e8b15eSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
421e1e8b15eSBrian Somers       o = &(*o)->next;
422e1e8b15eSBrian Somers 
42303036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
42403036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
425e1e8b15eSBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)(&(*o)->val);
42603036ec7SBrian Somers     if (ccp->out.state == NULL) {
427dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
428d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
42983d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
430dd7e2610SBrian Somers       fsm_Close(fp);
431479508cfSBrian Somers       return 0;
432247ab36dSBrian Somers     }
433af57ed9fSAtsushi Murai   }
434af57ed9fSAtsushi Murai 
435479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
436479508cfSBrian Somers 
437dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
438d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
43983d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
440479508cfSBrian Somers 
4416f384573SBrian Somers   return 1;
442af57ed9fSAtsushi Murai }
443af57ed9fSAtsushi Murai 
444af57ed9fSAtsushi Murai static void
44530c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
44630c2f2ffSBrian Somers                 struct fsm_decode *dec)
447af57ed9fSAtsushi Murai {
4487308ec68SBrian Somers   /* Deal with incoming data */
449aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
45031516407SBrian Somers   int type, length, f;
45103036ec7SBrian Somers   const char *end;
452af57ed9fSAtsushi Murai 
45331516407SBrian Somers   if (mode_type == MODE_REQ)
45431516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
45531516407SBrian Somers 
456af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
457af57ed9fSAtsushi Murai     type = *cp;
458af57ed9fSAtsushi Murai     length = cp[1];
45903036ec7SBrian Somers 
460d47dceb8SBrian Somers     if (length == 0) {
461dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
462d47dceb8SBrian Somers       break;
463d47dceb8SBrian Somers     }
464d47dceb8SBrian Somers 
46503036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
46603036ec7SBrian Somers       length = sizeof(struct lcp_opt);
467dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
468d47dceb8SBrian Somers                 fp->link->name, length);
46903036ec7SBrian Somers     }
470af57ed9fSAtsushi Murai 
4710053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
4720053cc58SBrian Somers       if (algorithm[f]->id == type)
4730053cc58SBrian Somers         break;
474af57ed9fSAtsushi Murai 
47503036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
47603036ec7SBrian Somers     if (end == NULL)
47703036ec7SBrian Somers       end = "";
47803036ec7SBrian Somers 
479d6d3eeabSBrian Somers     log_Printf(LogCCP, " %s[%d] %s\n", protoname(type), length, end);
48003036ec7SBrian Somers 
4810053cc58SBrian Somers     if (f == -1) {
4820053cc58SBrian Somers       /* Don't understand that :-( */
4830053cc58SBrian Somers       if (mode_type == MODE_REQ) {
48483d1af55SBrian Somers         ccp->my_reject |= (1 << type);
48530c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
48630c2f2ffSBrian Somers         dec->rejend += length;
4870053cc58SBrian Somers       }
4880053cc58SBrian Somers     } else {
48903036ec7SBrian Somers       struct ccp_opt *o;
4900053cc58SBrian Somers 
4919780ef31SBrian Somers       switch (mode_type) {
492af57ed9fSAtsushi Murai       case MODE_REQ:
4931342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
4941342caedSBrian Somers             ccp->in.algorithm == -1) {
49503036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
49603036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4970053cc58SBrian Somers           case MODE_REJ:
49803036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
49903036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
5000053cc58SBrian Somers             break;
5010053cc58SBrian Somers           case MODE_NAK:
50203036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
50303036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
5040053cc58SBrian Somers             break;
5050053cc58SBrian Somers           case MODE_ACK:
50630c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
50730c2f2ffSBrian Somers 	    dec->ackend += length;
50883d1af55SBrian Somers 	    ccp->his_proto = type;
50903036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
5100053cc58SBrian Somers             break;
5110053cc58SBrian Somers           }
512af57ed9fSAtsushi Murai 	} else {
51330c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
51430c2f2ffSBrian Somers 	  dec->rejend += length;
515af57ed9fSAtsushi Murai 	}
516af57ed9fSAtsushi Murai 	break;
517af57ed9fSAtsushi Murai       case MODE_NAK:
51803036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
51903036ec7SBrian Somers           if (o->val.id == cp[0])
52003036ec7SBrian Somers             break;
52103036ec7SBrian Somers         if (o == NULL)
5229b996792SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
5239b996792SBrian Somers                      " option\n", fp->link->name);
5240053cc58SBrian Somers         else {
52503036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
52603036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
52783d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
5281ae349f5Scvs2svn           else {
52983d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
53083d1af55SBrian Somers 	    ccp->my_proto = -1;
5311ae349f5Scvs2svn           }
5320053cc58SBrian Somers         }
5330053cc58SBrian Somers         break;
534af57ed9fSAtsushi Murai       case MODE_REJ:
53583d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
53683d1af55SBrian Somers 	ccp->my_proto = -1;
537af57ed9fSAtsushi Murai 	break;
538af57ed9fSAtsushi Murai       }
539af57ed9fSAtsushi Murai     }
5400053cc58SBrian Somers 
54103036ec7SBrian Somers     plen -= cp[1];
54203036ec7SBrian Somers     cp += cp[1];
543af57ed9fSAtsushi Murai   }
5440053cc58SBrian Somers 
545e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
5461342caedSBrian Somers     if (dec->rejend != dec->rej) {
54703036ec7SBrian Somers       /* rejects are preferred */
54803036ec7SBrian Somers       dec->ackend = dec->ack;
54903036ec7SBrian Somers       dec->nakend = dec->nak;
55003036ec7SBrian Somers       if (ccp->in.state == NULL) {
55183d1af55SBrian Somers         ccp->his_proto = -1;
55203036ec7SBrian Somers         ccp->in.algorithm = -1;
55303036ec7SBrian Somers       }
5541342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
55503036ec7SBrian Somers       /* then NAKs */
55603036ec7SBrian Somers       dec->ackend = dec->ack;
55703036ec7SBrian Somers       if (ccp->in.state == NULL) {
55803036ec7SBrian Somers         ccp->his_proto = -1;
55903036ec7SBrian Somers         ccp->in.algorithm = -1;
560247ab36dSBrian Somers       }
5611ae349f5Scvs2svn     }
5620053cc58SBrian Somers   }
563af57ed9fSAtsushi Murai }
564af57ed9fSAtsushi Murai 
5655d9e6103SBrian Somers extern struct mbuf *
5665d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
567af57ed9fSAtsushi Murai {
5687308ec68SBrian Somers   /* Got PROTO_CCP from link */
56926af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
570455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
5715d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
572af57ed9fSAtsushi Murai   else {
573641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
574dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
5755d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
57626af0ae9SBrian Somers     m_freem(bp);
577af57ed9fSAtsushi Murai   }
5785d9e6103SBrian Somers   return NULL;
579af57ed9fSAtsushi Murai }
5800053cc58SBrian Somers 
581503a7782SBrian Somers static void
582503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5830053cc58SBrian Somers {
5847308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
585f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
586f4768038SBrian Somers 
587f4768038SBrian Somers   if (ccp->reset_sent != -1) {
588f4768038SBrian Somers     if (id != ccp->reset_sent) {
589a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
590d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
59198baf7c8SBrian Somers       return;
59298baf7c8SBrian Somers     }
59398baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
594f4768038SBrian Somers   } else if (id == ccp->last_reset)
595dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
596d47dceb8SBrian Somers                fp->link->name);
59798baf7c8SBrian Somers   else {
598a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
599d47dceb8SBrian Somers                fp->link->name, id);
60098baf7c8SBrian Somers     return;
60198baf7c8SBrian Somers   }
60298baf7c8SBrian Somers 
603f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
604f4768038SBrian Somers   ccp->reset_sent = -1;
60503036ec7SBrian Somers   if (ccp->in.state != NULL)
60603036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
6070053cc58SBrian Somers }
6080053cc58SBrian Somers 
6095d9e6103SBrian Somers static struct mbuf *
6105d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
6115d9e6103SBrian Somers               int pri, u_short *proto)
6120053cc58SBrian Somers {
6135d9e6103SBrian Somers   if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED &&
614411675baSBrian Somers       l->ccp.out.state != NULL) {
615411675baSBrian Somers     bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
6165d9e6103SBrian Somers            (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
617411675baSBrian Somers     switch (*proto) {
618411675baSBrian Somers       case PROTO_ICOMPD:
61926af0ae9SBrian Somers         m_settype(bp, MB_ICOMPDOUT);
620411675baSBrian Somers         break;
621411675baSBrian Somers       case PROTO_COMPD:
62226af0ae9SBrian Somers         m_settype(bp, MB_COMPDOUT);
623411675baSBrian Somers         break;
624411675baSBrian Somers     }
625411675baSBrian Somers   }
6265d9e6103SBrian Somers 
6275d9e6103SBrian Somers   return bp;
6280053cc58SBrian Somers }
6290053cc58SBrian Somers 
6305d9e6103SBrian Somers static struct mbuf *
6315d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
6320053cc58SBrian Somers {
633ee6c193fSBrian Somers   /*
634ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
635ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
636ee6c193fSBrian Somers    */
6375d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
638ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
6396815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n",
6406815097bSBrian Somers                  *proto == PROTO_ICOMPD ? "I" : "");
6417308ec68SBrian Somers       /* Decompress incoming data */
6425d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
64398baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
644411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
645411675baSBrian Somers                    MB_CCPOUT);
646411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
647411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
6485d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
649411675baSBrian Somers         switch (*proto) {
650411675baSBrian Somers           case PROTO_ICOMPD:
65126af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
652411675baSBrian Somers             break;
653411675baSBrian Somers           case PROTO_COMPD:
65426af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
655411675baSBrian Somers             break;
656411675baSBrian Somers         }
657411675baSBrian Somers         return bp;
658411675baSBrian Somers       }
65926af0ae9SBrian Somers       m_freem(bp);
660ee6c193fSBrian Somers       bp = NULL;
6616815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
6626815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n");
663ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
6645d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
6655d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
6666815097bSBrian Somers     } else
6676815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n");
6680053cc58SBrian Somers   }
6690053cc58SBrian Somers 
670ee6c193fSBrian Somers   return bp;
6711ae349f5Scvs2svn }
672ed32233cSBrian Somers 
673ed32233cSBrian Somers u_short
674ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
6750053cc58SBrian Somers {
676ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
677ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
6780053cc58SBrian Somers }
6791df0a3b9SBrian Somers 
68006337856SBrian Somers int
6811df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
6821df0a3b9SBrian Somers {
6831df0a3b9SBrian Somers   int f;
6841df0a3b9SBrian Somers 
6851df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
68606337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
6871df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
68806337856SBrian Somers       return 1;
68906337856SBrian Somers     }
6901df0a3b9SBrian Somers 
69106337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
69206337856SBrian Somers 
69306337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
69406337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
69506337856SBrian Somers       return 1;
69606337856SBrian Somers 
69706337856SBrian Somers   return 0;				/* No CCP at all */
6981df0a3b9SBrian Somers }
6995d9e6103SBrian Somers 
7005d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
701