xref: /freebsd/usr.sbin/ppp/ccp.c (revision 26af0ae96638b0453bcc87cae6031eb0b3988171)
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"
44af57ed9fSAtsushi Murai #include "lcp.h"
45af57ed9fSAtsushi Murai #include "ccp.h"
46ed6a16c1SPoul-Henning Kamp #include "pred.h"
470053cc58SBrian Somers #include "deflate.h"
485828db6dSBrian Somers #include "throughput.h"
495828db6dSBrian Somers #include "iplist.h"
50eaa4df37SBrian Somers #include "slcompress.h"
515a72b6edSBrian Somers #include "lqr.h"
525a72b6edSBrian Somers #include "hdlc.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
643b0f8d2eSBrian Somers #include "bundle.h"
65af57ed9fSAtsushi Murai 
66927145beSBrian Somers static void CcpSendConfigReq(struct fsm *);
672267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
682267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
6930c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
7030c2f2ffSBrian Somers                             struct fsm_decode *);
71927145beSBrian Somers static void CcpLayerStart(struct fsm *);
72927145beSBrian Somers static void CcpLayerFinish(struct fsm *);
736f384573SBrian Somers static int CcpLayerUp(struct fsm *);
74927145beSBrian Somers static void CcpLayerDown(struct fsm *);
75479508cfSBrian Somers static void CcpInitRestartCounter(struct fsm *, int);
76503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
77503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
78af57ed9fSAtsushi Murai 
7983d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
80af57ed9fSAtsushi Murai   CcpLayerUp,
81af57ed9fSAtsushi Murai   CcpLayerDown,
82af57ed9fSAtsushi Murai   CcpLayerStart,
83af57ed9fSAtsushi Murai   CcpLayerFinish,
84af57ed9fSAtsushi Murai   CcpInitRestartCounter,
85af57ed9fSAtsushi Murai   CcpSendConfigReq,
862267893fSBrian Somers   CcpSentTerminateReq,
87af57ed9fSAtsushi Murai   CcpSendTerminateAck,
88af57ed9fSAtsushi Murai   CcpDecodeConfig,
89503a7782SBrian Somers   CcpRecvResetReq,
90503a7782SBrian Somers   CcpRecvResetAck
91af57ed9fSAtsushi Murai };
92af57ed9fSAtsushi Murai 
936f384573SBrian Somers static const char *ccp_TimerNames[] =
946f384573SBrian Somers   {"CCP restart", "CCP openmode", "CCP stopped"};
956f384573SBrian Somers 
96e53374eaSPoul-Henning Kamp static char const *cftypes[] = {
979e836af5SBrian Somers   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
989e836af5SBrian Somers   "OUI",		/* 0: OUI */
999e836af5SBrian Somers   "PRED1",		/* 1: Predictor type 1 */
1009e836af5SBrian Somers   "PRED2",		/* 2: Predictor type 2 */
1019e836af5SBrian Somers   "PUDDLE",		/* 3: Puddle Jumber */
1029e836af5SBrian Somers   "???", "???", "???", "???", "???", "???",
1039e836af5SBrian Somers   "???", "???", "???", "???", "???", "???",
1049e836af5SBrian Somers   "HWPPC",		/* 16: Hewlett-Packard PPC */
1054bc84b8cSBrian Somers   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
1068f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
1074bc84b8cSBrian Somers   "GAND",		/* 19: Gandalf FZA (rfc1993) */
108b6e82f33SBrian Somers   "V42BIS",		/* 20: ARG->DATA.42bis compression */
1090053cc58SBrian Somers   "BSD",		/* 21: BSD LZW Compress */
1100053cc58SBrian Somers   "???",
1114bc84b8cSBrian Somers   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1124bc84b8cSBrian Somers   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1131342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1144bc84b8cSBrian Somers   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1154bc84b8cSBrian Somers   "DEFLATE",		/* 26: Deflate (rfc1979) */
116af57ed9fSAtsushi Murai };
117af57ed9fSAtsushi Murai 
11870ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1199e836af5SBrian Somers 
1200053cc58SBrian Somers static const char *
1210053cc58SBrian Somers protoname(int proto)
1220053cc58SBrian Somers {
1230053cc58SBrian Somers   if (proto < 0 || proto > NCFTYPES)
1240053cc58SBrian Somers     return "none";
1250053cc58SBrian Somers   return cftypes[proto];
1260053cc58SBrian Somers }
1270053cc58SBrian Somers 
1284bc84b8cSBrian Somers /* We support these algorithms, and Req them in the given order */
1290053cc58SBrian Somers static const struct ccp_algorithm *algorithm[] = {
1304bc84b8cSBrian Somers   &DeflateAlgorithm,
1310053cc58SBrian Somers   &Pred1Algorithm,
1324bc84b8cSBrian Somers   &PppdDeflateAlgorithm
1330053cc58SBrian Somers };
1340053cc58SBrian Somers 
13570ee81ffSBrian Somers #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1360053cc58SBrian Somers 
137274e766cSBrian Somers int
138503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
139af57ed9fSAtsushi Murai {
140dd0645c5SBrian Somers   struct link *l;
141dd0645c5SBrian Somers   struct ccp *ccp;
142dd0645c5SBrian Somers 
1433a2e4f62SBrian Somers   l = command_ChooseLink(arg);
144dd0645c5SBrian Somers   ccp = &l->ccp;
145503a7782SBrian Somers 
146b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1471e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
1485d9e6103SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
149b6217683SBrian Somers     prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
150503a7782SBrian Somers                   protoname(ccp->my_proto), protoname(ccp->his_proto));
151b6217683SBrian Somers     prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
152503a7782SBrian Somers                   ccp->uncompout, ccp->compout,
153503a7782SBrian Somers                   ccp->compin, ccp->uncompin);
1545d9e6103SBrian Somers   }
155cd9647a1SBrian Somers 
156b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
157479508cfSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
158479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
159479508cfSBrian Somers                 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
160479508cfSBrian Somers                 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
161b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
162b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
163b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1641342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1651342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1661342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1671342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1681342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1691342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
170274e766cSBrian Somers   return 0;
171af57ed9fSAtsushi Murai }
172af57ed9fSAtsushi Murai 
1731ae349f5Scvs2svn void
1746f384573SBrian Somers ccp_SetupCallbacks(struct ccp *ccp)
175af57ed9fSAtsushi Murai {
1766f384573SBrian Somers   ccp->fsm.fn = &ccp_Callbacks;
1776f384573SBrian Somers   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
1786f384573SBrian Somers   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
1796f384573SBrian Somers   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
180ea661041SBrian Somers }
181ea661041SBrian Somers 
182ea661041SBrian Somers void
1836d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1846d666775SBrian Somers          const struct fsm_parent *parent)
185ea661041SBrian Somers {
1867308ec68SBrian Somers   /* Initialise ourselves */
1873b0f8d2eSBrian Somers 
188479508cfSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
1896f384573SBrian Somers            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
190cd9647a1SBrian Somers 
19103036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
19203036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
193479508cfSBrian Somers   ccp->cfg.fsm.timeout = DEF_FSMRETRY;
194479508cfSBrian Somers   ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
195479508cfSBrian Somers   ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
1961342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
1971342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
1981342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
199cd9647a1SBrian Somers 
200503a7782SBrian Somers   ccp_Setup(ccp);
201503a7782SBrian Somers }
202503a7782SBrian Somers 
203503a7782SBrian Somers void
204503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
205503a7782SBrian Somers {
206503a7782SBrian Somers   /* Set ourselves up for a startup */
207503a7782SBrian Somers   ccp->fsm.open_mode = 0;
208503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
209503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
21003036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
21103036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
21203036ec7SBrian Somers   ccp->in.opt.id = -1;
21303036ec7SBrian Somers   ccp->out.opt = NULL;
214503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
215503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
216503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
217af57ed9fSAtsushi Murai }
218af57ed9fSAtsushi Murai 
219af57ed9fSAtsushi Murai static void
220479508cfSBrian Somers CcpInitRestartCounter(struct fsm *fp, int what)
221af57ed9fSAtsushi Murai {
2227308ec68SBrian Somers   /* Set fsm timer load */
223cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
224cd9647a1SBrian Somers 
225479508cfSBrian Somers   fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
226479508cfSBrian Somers   switch (what) {
227479508cfSBrian Somers     case FSM_REQ_TIMER:
228479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxreq;
229479508cfSBrian Somers       break;
230479508cfSBrian Somers     case FSM_TRM_TIMER:
231479508cfSBrian Somers       fp->restart = ccp->cfg.fsm.maxtrm;
232479508cfSBrian Somers       break;
233479508cfSBrian Somers     default:
234479508cfSBrian Somers       fp->restart = 1;
235479508cfSBrian Somers       break;
236479508cfSBrian Somers   }
237af57ed9fSAtsushi Murai }
238af57ed9fSAtsushi Murai 
239af57ed9fSAtsushi Murai static void
240944f7098SBrian Somers CcpSendConfigReq(struct fsm *fp)
241af57ed9fSAtsushi Murai {
2427308ec68SBrian Somers   /* Send config REQ please */
243aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
24403036ec7SBrian Somers   struct ccp_opt **o;
24530c2f2ffSBrian Somers   u_char *cp, buff[100];
24603036ec7SBrian Somers   int f, alloc;
247af57ed9fSAtsushi Murai 
24830c2f2ffSBrian Somers   cp = buff;
24903036ec7SBrian Somers   o = &ccp->out.opt;
25003036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
25183d1af55SBrian Somers   ccp->my_proto = -1;
25203036ec7SBrian Somers   ccp->out.algorithm = -1;
2530053cc58SBrian Somers   for (f = 0; f < NALGORITHMS; f++)
2541342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2551342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
2560053cc58SBrian Somers 
257ba081e43SBrian Somers       if (!alloc)
258ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
259ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
260ba081e43SBrian Somers             break;
261ba081e43SBrian Somers 
262ba081e43SBrian Somers       if (alloc || *o == NULL) {
26303036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
26403036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
26503036ec7SBrian Somers         (*o)->val.len = 2;
26603036ec7SBrian Somers         (*o)->next = NULL;
26703036ec7SBrian Somers         (*o)->algorithm = f;
26803036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
269af57ed9fSAtsushi Murai       }
2701ae349f5Scvs2svn 
27103036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
272dd7e2610SBrian Somers         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
27330c2f2ffSBrian Somers         break;
27430c2f2ffSBrian Somers       }
2752267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2762267893fSBrian Somers       cp += (*o)->val.len;
27703036ec7SBrian Somers 
27803036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
27903036ec7SBrian Somers       ccp->out.algorithm = f;
28003036ec7SBrian Somers 
28103036ec7SBrian Somers       if (alloc)
28203036ec7SBrian Somers         o = &(*o)->next;
2831ae349f5Scvs2svn     }
2842267893fSBrian Somers 
285411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
286af57ed9fSAtsushi Murai }
287af57ed9fSAtsushi Murai 
288af57ed9fSAtsushi Murai void
289dd7e2610SBrian Somers ccp_SendResetReq(struct fsm *fp)
290af57ed9fSAtsushi Murai {
2917308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
292aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2932267893fSBrian Somers 
29483d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
29583d1af55SBrian Somers   ccp->last_reset = -1;
296411675baSBrian Somers   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
297af57ed9fSAtsushi Murai }
298af57ed9fSAtsushi Murai 
299af57ed9fSAtsushi Murai static void
3002267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
301af57ed9fSAtsushi Murai {
3027308ec68SBrian Somers   /* Term REQ just sent by FSM */
303af57ed9fSAtsushi Murai }
304af57ed9fSAtsushi Murai 
305af57ed9fSAtsushi Murai static void
3062267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
307af57ed9fSAtsushi Murai {
3087308ec68SBrian Somers   /* Send Term ACK please */
309411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
310af57ed9fSAtsushi Murai }
311af57ed9fSAtsushi Murai 
312503a7782SBrian Somers static void
313944f7098SBrian Somers CcpRecvResetReq(struct fsm *fp)
314af57ed9fSAtsushi Murai {
3157308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
316aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
31703036ec7SBrian Somers   if (ccp->out.state != NULL)
31803036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
319af57ed9fSAtsushi Murai }
320af57ed9fSAtsushi Murai 
321af57ed9fSAtsushi Murai static void
322944f7098SBrian Somers CcpLayerStart(struct fsm *fp)
323af57ed9fSAtsushi Murai {
3247308ec68SBrian Somers   /* We're about to start up ! */
325479508cfSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
326479508cfSBrian Somers 
3273a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
328479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
329af57ed9fSAtsushi Murai }
330af57ed9fSAtsushi Murai 
331af57ed9fSAtsushi Murai static void
332897f9429SBrian Somers CcpLayerDown(struct fsm *fp)
333af57ed9fSAtsushi Murai {
334897f9429SBrian Somers   /* About to come down */
335aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
336ba081e43SBrian Somers   struct ccp_opt *next;
337ba081e43SBrian Somers 
3383a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
33903036ec7SBrian Somers   if (ccp->in.state != NULL) {
34003036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
34103036ec7SBrian Somers     ccp->in.state = NULL;
3428d9b9867SBrian Somers     ccp->in.algorithm = -1;
3437308ec68SBrian Somers   }
34403036ec7SBrian Somers   if (ccp->out.state != NULL) {
34503036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
34603036ec7SBrian Somers     ccp->out.state = NULL;
3478d9b9867SBrian Somers     ccp->out.algorithm = -1;
3487308ec68SBrian Somers   }
3498d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
350ba081e43SBrian Somers 
351ba081e43SBrian Somers   while (ccp->out.opt) {
352ba081e43SBrian Somers     next = ccp->out.opt->next;
353ba081e43SBrian Somers     free(ccp->out.opt);
354ba081e43SBrian Somers     ccp->out.opt = next;
355ba081e43SBrian Somers   }
356897f9429SBrian Somers   ccp_Setup(ccp);
357af57ed9fSAtsushi Murai }
358af57ed9fSAtsushi Murai 
359af57ed9fSAtsushi Murai static void
360897f9429SBrian Somers CcpLayerFinish(struct fsm *fp)
361af57ed9fSAtsushi Murai {
362897f9429SBrian Somers   /* We're now down */
3633a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
364af57ed9fSAtsushi Murai }
365af57ed9fSAtsushi Murai 
3663377c28cSBrian Somers /*  Called when CCP has reached the OPEN state */
3676f384573SBrian Somers static int
368944f7098SBrian Somers CcpLayerUp(struct fsm *fp)
369af57ed9fSAtsushi Murai {
3707308ec68SBrian Somers   /* We're now up */
371aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
372479508cfSBrian Somers 
3733a2e4f62SBrian Somers   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
374479508cfSBrian Somers 
37503036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
37603036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
37703036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
37803036ec7SBrian Somers     if (ccp->in.state == NULL) {
379dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
380d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
38183d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
382dd7e2610SBrian Somers       fsm_Close(fp);
383479508cfSBrian Somers       return 0;
38479d1bdaeSBrian Somers     }
385af57ed9fSAtsushi Murai   }
386af57ed9fSAtsushi Murai 
38703036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
38803036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
38903036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
39003036ec7SBrian Somers                        (&ccp->out.opt->val);
39103036ec7SBrian Somers     if (ccp->out.state == NULL) {
392dd7e2610SBrian Somers       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
393d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
39483d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
395dd7e2610SBrian Somers       fsm_Close(fp);
396479508cfSBrian Somers       return 0;
397247ab36dSBrian Somers     }
398af57ed9fSAtsushi Murai   }
399af57ed9fSAtsushi Murai 
400479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
401479508cfSBrian Somers 
402dd7e2610SBrian Somers   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
403d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
40483d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
405479508cfSBrian Somers 
4066f384573SBrian Somers   return 1;
407af57ed9fSAtsushi Murai }
408af57ed9fSAtsushi Murai 
409af57ed9fSAtsushi Murai static void
41030c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
41130c2f2ffSBrian Somers                 struct fsm_decode *dec)
412af57ed9fSAtsushi Murai {
4137308ec68SBrian Somers   /* Deal with incoming data */
414aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
41531516407SBrian Somers   int type, length, f;
41603036ec7SBrian Somers   const char *end;
417af57ed9fSAtsushi Murai 
41831516407SBrian Somers   if (mode_type == MODE_REQ)
41931516407SBrian Somers     ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
42031516407SBrian Somers 
421af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
422af57ed9fSAtsushi Murai     type = *cp;
423af57ed9fSAtsushi Murai     length = cp[1];
42403036ec7SBrian Somers 
425d47dceb8SBrian Somers     if (length == 0) {
426dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
427d47dceb8SBrian Somers       break;
428d47dceb8SBrian Somers     }
429d47dceb8SBrian Somers 
43003036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
43103036ec7SBrian Somers       length = sizeof(struct lcp_opt);
432dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
433d47dceb8SBrian Somers                 fp->link->name, length);
43403036ec7SBrian Somers     }
435af57ed9fSAtsushi Murai 
4360053cc58SBrian Somers     for (f = NALGORITHMS-1; f > -1; f--)
4370053cc58SBrian Somers       if (algorithm[f]->id == type)
4380053cc58SBrian Somers         break;
439af57ed9fSAtsushi Murai 
44003036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
44103036ec7SBrian Somers     if (end == NULL)
44203036ec7SBrian Somers       end = "";
44303036ec7SBrian Somers 
44403036ec7SBrian Somers     if (type < NCFTYPES)
445dd7e2610SBrian Somers       log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
44603036ec7SBrian Somers     else
447dd7e2610SBrian Somers       log_Printf(LogCCP, " ???[%d] %s\n", length, end);
44803036ec7SBrian Somers 
4490053cc58SBrian Somers     if (f == -1) {
4500053cc58SBrian Somers       /* Don't understand that :-( */
4510053cc58SBrian Somers       if (mode_type == MODE_REQ) {
45283d1af55SBrian Somers         ccp->my_reject |= (1 << type);
45330c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
45430c2f2ffSBrian Somers         dec->rejend += length;
4550053cc58SBrian Somers       }
4560053cc58SBrian Somers     } else {
45703036ec7SBrian Somers       struct ccp_opt *o;
4580053cc58SBrian Somers 
4599780ef31SBrian Somers       switch (mode_type) {
460af57ed9fSAtsushi Murai       case MODE_REQ:
4611342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
4621342caedSBrian Somers             ccp->in.algorithm == -1) {
46303036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
46403036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4650053cc58SBrian Somers           case MODE_REJ:
46603036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
46703036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4680053cc58SBrian Somers             break;
4690053cc58SBrian Somers           case MODE_NAK:
47003036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
47103036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4720053cc58SBrian Somers             break;
4730053cc58SBrian Somers           case MODE_ACK:
47430c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
47530c2f2ffSBrian Somers 	    dec->ackend += length;
47683d1af55SBrian Somers 	    ccp->his_proto = type;
47703036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4780053cc58SBrian Somers             break;
4790053cc58SBrian Somers           }
480af57ed9fSAtsushi Murai 	} else {
48130c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
48230c2f2ffSBrian Somers 	  dec->rejend += length;
483af57ed9fSAtsushi Murai 	}
484af57ed9fSAtsushi Murai 	break;
485af57ed9fSAtsushi Murai       case MODE_NAK:
48603036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
48703036ec7SBrian Somers           if (o->val.id == cp[0])
48803036ec7SBrian Somers             break;
48903036ec7SBrian Somers         if (o == NULL)
490dd7e2610SBrian Somers           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n",
491d47dceb8SBrian Somers                     fp->link->name);
4920053cc58SBrian Somers         else {
49303036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
49403036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
49583d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4961ae349f5Scvs2svn           else {
49783d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
49883d1af55SBrian Somers 	    ccp->my_proto = -1;
4991ae349f5Scvs2svn           }
5000053cc58SBrian Somers         }
5010053cc58SBrian Somers         break;
502af57ed9fSAtsushi Murai       case MODE_REJ:
50383d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
50483d1af55SBrian Somers 	ccp->my_proto = -1;
505af57ed9fSAtsushi Murai 	break;
506af57ed9fSAtsushi Murai       }
507af57ed9fSAtsushi Murai     }
5080053cc58SBrian Somers 
50903036ec7SBrian Somers     plen -= cp[1];
51003036ec7SBrian Somers     cp += cp[1];
511af57ed9fSAtsushi Murai   }
5120053cc58SBrian Somers 
513e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
5141342caedSBrian Somers     if (dec->rejend != dec->rej) {
51503036ec7SBrian Somers       /* rejects are preferred */
51603036ec7SBrian Somers       dec->ackend = dec->ack;
51703036ec7SBrian Somers       dec->nakend = dec->nak;
51803036ec7SBrian Somers       if (ccp->in.state == NULL) {
51983d1af55SBrian Somers         ccp->his_proto = -1;
52003036ec7SBrian Somers         ccp->in.algorithm = -1;
52103036ec7SBrian Somers       }
5221342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
52303036ec7SBrian Somers       /* then NAKs */
52403036ec7SBrian Somers       dec->ackend = dec->ack;
52503036ec7SBrian Somers       if (ccp->in.state == NULL) {
52603036ec7SBrian Somers         ccp->his_proto = -1;
52703036ec7SBrian Somers         ccp->in.algorithm = -1;
528247ab36dSBrian Somers       }
5291ae349f5Scvs2svn     }
5300053cc58SBrian Somers   }
531af57ed9fSAtsushi Murai }
532af57ed9fSAtsushi Murai 
5335d9e6103SBrian Somers extern struct mbuf *
5345d9e6103SBrian Somers ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
535af57ed9fSAtsushi Murai {
5367308ec68SBrian Somers   /* Got PROTO_CCP from link */
53726af0ae9SBrian Somers   m_settype(bp, MB_CCPIN);
538455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
5395d9e6103SBrian Somers     fsm_Input(&l->ccp.fsm, bp);
540af57ed9fSAtsushi Murai   else {
541641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
542dd7e2610SBrian Somers       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
5435d9e6103SBrian Somers                  l->ccp.fsm.link->name, bundle_PhaseName(bundle));
54426af0ae9SBrian Somers     m_freem(bp);
545af57ed9fSAtsushi Murai   }
5465d9e6103SBrian Somers   return NULL;
547af57ed9fSAtsushi Murai }
5480053cc58SBrian Somers 
549503a7782SBrian Somers static void
550503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5510053cc58SBrian Somers {
5527308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
553f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
554f4768038SBrian Somers 
555f4768038SBrian Somers   if (ccp->reset_sent != -1) {
556f4768038SBrian Somers     if (id != ccp->reset_sent) {
557a36ca3ccSBrian Somers       log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
558d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
55998baf7c8SBrian Somers       return;
56098baf7c8SBrian Somers     }
56198baf7c8SBrian Somers     /* Whaddaya know - a correct reset ack */
562f4768038SBrian Somers   } else if (id == ccp->last_reset)
563dd7e2610SBrian Somers     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
564d47dceb8SBrian Somers                fp->link->name);
56598baf7c8SBrian Somers   else {
566a36ca3ccSBrian Somers     log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
567d47dceb8SBrian Somers                fp->link->name, id);
56898baf7c8SBrian Somers     return;
56998baf7c8SBrian Somers   }
57098baf7c8SBrian Somers 
571f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
572f4768038SBrian Somers   ccp->reset_sent = -1;
57303036ec7SBrian Somers   if (ccp->in.state != NULL)
57403036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5750053cc58SBrian Somers }
5760053cc58SBrian Somers 
5775d9e6103SBrian Somers static struct mbuf *
5785d9e6103SBrian Somers ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
5795d9e6103SBrian Somers               int pri, u_short *proto)
5800053cc58SBrian Somers {
5815d9e6103SBrian Somers   if (PROTO_COMPRESSIBLE(*proto) && l->ccp.fsm.state == ST_OPENED &&
582411675baSBrian Somers       l->ccp.out.state != NULL) {
583411675baSBrian Somers     bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
5845d9e6103SBrian Somers            (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
585411675baSBrian Somers     switch (*proto) {
586411675baSBrian Somers       case PROTO_ICOMPD:
58726af0ae9SBrian Somers         m_settype(bp, MB_ICOMPDOUT);
588411675baSBrian Somers         break;
589411675baSBrian Somers       case PROTO_COMPD:
59026af0ae9SBrian Somers         m_settype(bp, MB_COMPDOUT);
591411675baSBrian Somers         break;
592411675baSBrian Somers     }
593411675baSBrian Somers   }
5945d9e6103SBrian Somers 
5955d9e6103SBrian Somers   return bp;
5960053cc58SBrian Somers }
5970053cc58SBrian Somers 
5985d9e6103SBrian Somers static struct mbuf *
5995d9e6103SBrian Somers ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
6000053cc58SBrian Somers {
601ee6c193fSBrian Somers   /*
602ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
603ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
604ee6c193fSBrian Somers    */
6055d9e6103SBrian Somers   if (l->ccp.fsm.state == ST_OPENED) {
606ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
6076815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n",
6086815097bSBrian Somers                  *proto == PROTO_ICOMPD ? "I" : "");
6097308ec68SBrian Somers       /* Decompress incoming data */
6105d9e6103SBrian Somers       if (l->ccp.reset_sent != -1)
61198baf7c8SBrian Somers         /* Send another REQ and put the packet in the bit bucket */
612411675baSBrian Somers         fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
613411675baSBrian Somers                    MB_CCPOUT);
614411675baSBrian Somers       else if (l->ccp.in.state != NULL) {
615411675baSBrian Somers         bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
6165d9e6103SBrian Somers                (l->ccp.in.state, &l->ccp, proto, bp);
617411675baSBrian Somers         switch (*proto) {
618411675baSBrian Somers           case PROTO_ICOMPD:
61926af0ae9SBrian Somers             m_settype(bp, MB_ICOMPDIN);
620411675baSBrian Somers             break;
621411675baSBrian Somers           case PROTO_COMPD:
62226af0ae9SBrian Somers             m_settype(bp, MB_COMPDIN);
623411675baSBrian Somers             break;
624411675baSBrian Somers         }
625411675baSBrian Somers         return bp;
626411675baSBrian Somers       }
62726af0ae9SBrian Somers       m_freem(bp);
628ee6c193fSBrian Somers       bp = NULL;
6296815097bSBrian Somers     } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
6306815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n");
631ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
6325d9e6103SBrian Somers       (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
6335d9e6103SBrian Somers         (l->ccp.in.state, &l->ccp, *proto, bp);
6346815097bSBrian Somers     } else
6356815097bSBrian Somers       log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n");
6360053cc58SBrian Somers   }
6370053cc58SBrian Somers 
638ee6c193fSBrian Somers   return bp;
6391ae349f5Scvs2svn }
640ed32233cSBrian Somers 
641ed32233cSBrian Somers u_short
642ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
6430053cc58SBrian Somers {
644ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
645ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
6460053cc58SBrian Somers }
6471df0a3b9SBrian Somers 
64806337856SBrian Somers int
6491df0a3b9SBrian Somers ccp_SetOpenMode(struct ccp *ccp)
6501df0a3b9SBrian Somers {
6511df0a3b9SBrian Somers   int f;
6521df0a3b9SBrian Somers 
6531df0a3b9SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
65406337856SBrian Somers     if (IsEnabled(ccp->cfg.neg[f])) {
6551df0a3b9SBrian Somers       ccp->fsm.open_mode = 0;
65606337856SBrian Somers       return 1;
65706337856SBrian Somers     }
6581df0a3b9SBrian Somers 
65906337856SBrian Somers   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
66006337856SBrian Somers 
66106337856SBrian Somers   for (f = 0; f < CCP_NEG_TOTAL; f++)
66206337856SBrian Somers     if (IsAccepted(ccp->cfg.neg[f]))
66306337856SBrian Somers       return 1;
66406337856SBrian Somers 
66506337856SBrian Somers   return 0;				/* No CCP at all */
6661df0a3b9SBrian Somers }
6675d9e6103SBrian Somers 
6685d9e6103SBrian Somers struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
669