xref: /freebsd/usr.sbin/ppp/ccp.c (revision 1fa665f5b363853f2e5ebdf453e9af3b7e752729)
11ae349f5Scvs2svn /*
21ae349f5Scvs2svn  *	   PPP Compression Control Protocol (CCP) Module
31ae349f5Scvs2svn  *
41ae349f5Scvs2svn  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51ae349f5Scvs2svn  *
61ae349f5Scvs2svn  *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
71ae349f5Scvs2svn  *
81ae349f5Scvs2svn  * Redistribution and use in source and binary forms are permitted
91ae349f5Scvs2svn  * provided that the above copyright notice and this paragraph are
101ae349f5Scvs2svn  * duplicated in all such forms and that any documentation,
111ae349f5Scvs2svn  * advertising materials, and other materials related to such
121ae349f5Scvs2svn  * distribution and use acknowledge that the software was developed
131ae349f5Scvs2svn  * by the Internet Initiative Japan, Inc.  The name of the
141ae349f5Scvs2svn  * IIJ may not be used to endorse or promote products derived
151ae349f5Scvs2svn  * from this software without specific prior written permission.
161ae349f5Scvs2svn  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171ae349f5Scvs2svn  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181ae349f5Scvs2svn  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191ae349f5Scvs2svn  *
201fa665f5SBrian Somers  * $Id: ccp.c,v 1.30.2.39 1998/04/25 10:48:49 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o Support other compression protocols
241ae349f5Scvs2svn  */
252764b86aSBrian Somers #include <sys/types.h>
261ae349f5Scvs2svn #include <netinet/in.h>
27eaa4df37SBrian Somers #include <netinet/in_systm.h>
28eaa4df37SBrian Somers #include <netinet/ip.h>
291fa665f5SBrian Somers #include <sys/un.h>
301ae349f5Scvs2svn 
311ae349f5Scvs2svn #include <stdio.h>
3203036ec7SBrian Somers #include <stdlib.h>
3385b542cfSBrian Somers #include <termios.h>
341ae349f5Scvs2svn 
351ae349f5Scvs2svn #include "command.h"
361ae349f5Scvs2svn #include "mbuf.h"
371ae349f5Scvs2svn #include "log.h"
381ae349f5Scvs2svn #include "defs.h"
391ae349f5Scvs2svn #include "timer.h"
401ae349f5Scvs2svn #include "fsm.h"
411ae349f5Scvs2svn #include "lcpproto.h"
421ae349f5Scvs2svn #include "lcp.h"
431ae349f5Scvs2svn #include "ccp.h"
441ae349f5Scvs2svn #include "pred.h"
451ae349f5Scvs2svn #include "deflate.h"
465828db6dSBrian Somers #include "throughput.h"
475828db6dSBrian Somers #include "iplist.h"
48eaa4df37SBrian Somers #include "slcompress.h"
495828db6dSBrian Somers #include "ipcp.h"
505ca5389aSBrian Somers #include "filter.h"
5185b542cfSBrian Somers #include "descriptor.h"
5285b542cfSBrian Somers #include "prompt.h"
53879ed6faSBrian Somers #include "lqr.h"
54503a7782SBrian Somers #include "hdlc.h"
55503a7782SBrian Somers #include "link.h"
563b0f8d2eSBrian Somers #include "mp.h"
57ed32233cSBrian Somers #include "async.h"
58ed32233cSBrian Somers #include "physical.h"
593b0f8d2eSBrian Somers #include "bundle.h"
601ae349f5Scvs2svn 
611ae349f5Scvs2svn static void CcpSendConfigReq(struct fsm *);
622267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
632267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
6430c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
6530c2f2ffSBrian Somers                             struct fsm_decode *);
661ae349f5Scvs2svn static void CcpLayerStart(struct fsm *);
671ae349f5Scvs2svn static void CcpLayerFinish(struct fsm *);
681ae349f5Scvs2svn static void CcpLayerUp(struct fsm *);
691ae349f5Scvs2svn static void CcpLayerDown(struct fsm *);
701ae349f5Scvs2svn static void CcpInitRestartCounter(struct fsm *);
71503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
72503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
731ae349f5Scvs2svn 
7483d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
7583d1af55SBrian Somers   CcpLayerUp,
7683d1af55SBrian Somers   CcpLayerDown,
7783d1af55SBrian Somers   CcpLayerStart,
786d666775SBrian Somers   CcpLayerFinish,
7983d1af55SBrian Somers   CcpInitRestartCounter,
8083d1af55SBrian Somers   CcpSendConfigReq,
812267893fSBrian Somers   CcpSentTerminateReq,
8283d1af55SBrian Somers   CcpSendTerminateAck,
83503a7782SBrian Somers   CcpDecodeConfig,
84503a7782SBrian Somers   CcpRecvResetReq,
85503a7782SBrian Somers   CcpRecvResetAck
8683d1af55SBrian Somers };
8783d1af55SBrian Somers 
881ae349f5Scvs2svn static char const *cftypes[] = {
891ae349f5Scvs2svn   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
901ae349f5Scvs2svn   "OUI",		/* 0: OUI */
911ae349f5Scvs2svn   "PRED1",		/* 1: Predictor type 1 */
921ae349f5Scvs2svn   "PRED2",		/* 2: Predictor type 2 */
931ae349f5Scvs2svn   "PUDDLE",		/* 3: Puddle Jumber */
941ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
951ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
961ae349f5Scvs2svn   "HWPPC",		/* 16: Hewlett-Packard PPC */
971ae349f5Scvs2svn   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
988f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
991ae349f5Scvs2svn   "GAND",		/* 19: Gandalf FZA (rfc1993) */
1001ae349f5Scvs2svn   "V42BIS",		/* 20: ARG->DATA.42bis compression */
1011ae349f5Scvs2svn   "BSD",		/* 21: BSD LZW Compress */
1021ae349f5Scvs2svn   "???",
1031ae349f5Scvs2svn   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1041ae349f5Scvs2svn   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1051342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1061ae349f5Scvs2svn   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1071ae349f5Scvs2svn   "DEFLATE",		/* 26: Deflate (rfc1979) */
1081ae349f5Scvs2svn };
1091ae349f5Scvs2svn 
1101ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1111ae349f5Scvs2svn 
1121ae349f5Scvs2svn static const char *
1131ae349f5Scvs2svn protoname(int proto)
1141ae349f5Scvs2svn {
1151ae349f5Scvs2svn   if (proto < 0 || proto > NCFTYPES)
1161ae349f5Scvs2svn     return "none";
1171ae349f5Scvs2svn   return cftypes[proto];
1181ae349f5Scvs2svn }
1191ae349f5Scvs2svn 
1201ae349f5Scvs2svn /* We support these algorithms, and Req them in the given order */
1211ae349f5Scvs2svn static const struct ccp_algorithm *algorithm[] = {
1221ae349f5Scvs2svn   &DeflateAlgorithm,
1231ae349f5Scvs2svn   &Pred1Algorithm,
1241ae349f5Scvs2svn   &PppdDeflateAlgorithm
1251ae349f5Scvs2svn };
1261ae349f5Scvs2svn 
1271ae349f5Scvs2svn #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1281ae349f5Scvs2svn 
1291ae349f5Scvs2svn int
130503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
1311ae349f5Scvs2svn {
132cd9647a1SBrian Somers   struct link *l = ChooseLink(arg);
133cd9647a1SBrian Somers   struct ccp *ccp = &l->ccp;
134503a7782SBrian Somers 
135b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1361e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
137b6217683SBrian Somers   prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
138503a7782SBrian Somers                 protoname(ccp->my_proto), protoname(ccp->his_proto));
139b6217683SBrian Somers   prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
140503a7782SBrian Somers                 ccp->uncompout, ccp->compout,
141503a7782SBrian Somers                 ccp->compin, ccp->uncompin);
142cd9647a1SBrian Somers 
143b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
1441342caedSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry);
145b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
146b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
147b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1481342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1491342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1501342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1511342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1521342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1531342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
1541ae349f5Scvs2svn   return 0;
1551ae349f5Scvs2svn }
1561ae349f5Scvs2svn 
1571ae349f5Scvs2svn void
1586d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1596d666775SBrian Somers          const struct fsm_parent *parent)
1601ae349f5Scvs2svn {
1617308ec68SBrian Somers   /* Initialise ourselves */
1623b0f8d2eSBrian Somers   static const char *timer_names[] =
1633b0f8d2eSBrian Somers     {"CCP restart", "CCP openmode", "CCP stopped"};
1643b0f8d2eSBrian Somers 
1653b0f8d2eSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
1663b0f8d2eSBrian Somers            bundle, l, parent, &ccp_Callbacks, timer_names);
167cd9647a1SBrian Somers 
16803036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
16903036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
170cd9647a1SBrian Somers   ccp->cfg.fsmretry = DEF_FSMRETRY;
1711342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
1721342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
1731342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
174cd9647a1SBrian Somers 
175503a7782SBrian Somers   ccp_Setup(ccp);
176503a7782SBrian Somers }
177503a7782SBrian Somers 
178503a7782SBrian Somers void
179503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
180503a7782SBrian Somers {
181503a7782SBrian Somers   /* Set ourselves up for a startup */
182503a7782SBrian Somers   ccp->fsm.open_mode = 0;
1835454ccd9SBrian Somers   ccp->fsm.maxconfig = 10;
184503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
185503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
18603036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
18703036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
18803036ec7SBrian Somers   ccp->in.opt.id = -1;
18903036ec7SBrian Somers   ccp->out.opt = NULL;
190503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
191503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
192503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
1931ae349f5Scvs2svn }
1941ae349f5Scvs2svn 
1951ae349f5Scvs2svn static void
1961ae349f5Scvs2svn CcpInitRestartCounter(struct fsm *fp)
1971ae349f5Scvs2svn {
1987308ec68SBrian Somers   /* Set fsm timer load */
199cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
200cd9647a1SBrian Somers 
201cd9647a1SBrian Somers   fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS;
2021ae349f5Scvs2svn   fp->restart = 5;
2031ae349f5Scvs2svn }
2041ae349f5Scvs2svn 
2051ae349f5Scvs2svn static void
2061ae349f5Scvs2svn CcpSendConfigReq(struct fsm *fp)
2071ae349f5Scvs2svn {
2087308ec68SBrian Somers   /* Send config REQ please */
209aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
21003036ec7SBrian Somers   struct ccp_opt **o;
21130c2f2ffSBrian Somers   u_char *cp, buff[100];
21203036ec7SBrian Somers   int f, alloc;
2131ae349f5Scvs2svn 
21430c2f2ffSBrian Somers   cp = buff;
21503036ec7SBrian Somers   o = &ccp->out.opt;
21603036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
21783d1af55SBrian Somers   ccp->my_proto = -1;
21803036ec7SBrian Somers   ccp->out.algorithm = -1;
2191ae349f5Scvs2svn   for (f = 0; f < NALGORITHMS; f++)
2201342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2211342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
222ba081e43SBrian Somers 
223ba081e43SBrian Somers       if (!alloc)
224ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
225ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
226ba081e43SBrian Somers             break;
227ba081e43SBrian Somers 
228ba081e43SBrian Somers       if (alloc || *o == NULL) {
22903036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
23003036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
23103036ec7SBrian Somers         (*o)->val.len = 2;
23203036ec7SBrian Somers         (*o)->next = NULL;
23303036ec7SBrian Somers         (*o)->algorithm = f;
23403036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
23503036ec7SBrian Somers       }
2361ae349f5Scvs2svn 
23703036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
238d47dceb8SBrian Somers         LogPrintf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
23930c2f2ffSBrian Somers         break;
24030c2f2ffSBrian Somers       }
2412267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2422267893fSBrian Somers       cp += (*o)->val.len;
24303036ec7SBrian Somers 
24403036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
24503036ec7SBrian Somers       ccp->out.algorithm = f;
24603036ec7SBrian Somers 
24703036ec7SBrian Somers       if (alloc)
24803036ec7SBrian Somers         o = &(*o)->next;
2491ae349f5Scvs2svn     }
2502267893fSBrian Somers 
2512267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff);
2521ae349f5Scvs2svn }
2531ae349f5Scvs2svn 
2541ae349f5Scvs2svn void
2551ae349f5Scvs2svn CcpSendResetReq(struct fsm *fp)
2561ae349f5Scvs2svn {
2577308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
258aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2592267893fSBrian Somers 
26083d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
26183d1af55SBrian Somers   ccp->last_reset = -1;
2621ae349f5Scvs2svn   FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
2631ae349f5Scvs2svn }
2641ae349f5Scvs2svn 
2651ae349f5Scvs2svn static void
2662267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
2671ae349f5Scvs2svn {
2687308ec68SBrian Somers   /* Term REQ just sent by FSM */
2691ae349f5Scvs2svn }
2701ae349f5Scvs2svn 
2711ae349f5Scvs2svn static void
2722267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
2731ae349f5Scvs2svn {
2747308ec68SBrian Somers   /* Send Term ACK please */
2752267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
2761ae349f5Scvs2svn }
2771ae349f5Scvs2svn 
278503a7782SBrian Somers static void
2791ae349f5Scvs2svn CcpRecvResetReq(struct fsm *fp)
2801ae349f5Scvs2svn {
2817308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
282aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
28303036ec7SBrian Somers   if (ccp->out.state != NULL)
28403036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
2851ae349f5Scvs2svn }
2861ae349f5Scvs2svn 
2871ae349f5Scvs2svn static void
2881ae349f5Scvs2svn CcpLayerStart(struct fsm *fp)
2891ae349f5Scvs2svn {
2907308ec68SBrian Somers   /* We're about to start up ! */
291d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerStart.\n", fp->link->name);
2921ae349f5Scvs2svn }
2931ae349f5Scvs2svn 
2941ae349f5Scvs2svn static void
2951ae349f5Scvs2svn CcpLayerFinish(struct fsm *fp)
2961ae349f5Scvs2svn {
2977308ec68SBrian Somers   /* We're now down */
298aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
299ba081e43SBrian Somers   struct ccp_opt *next;
300ba081e43SBrian Somers 
301d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerFinish.\n", fp->link->name);
30203036ec7SBrian Somers   if (ccp->in.state != NULL) {
30303036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
30403036ec7SBrian Somers     ccp->in.state = NULL;
3058d9b9867SBrian Somers     ccp->in.algorithm = -1;
3067308ec68SBrian Somers   }
30703036ec7SBrian Somers   if (ccp->out.state != NULL) {
30803036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
30903036ec7SBrian Somers     ccp->out.state = NULL;
3108d9b9867SBrian Somers     ccp->out.algorithm = -1;
3117308ec68SBrian Somers   }
3128d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
313ba081e43SBrian Somers 
314ba081e43SBrian Somers   while (ccp->out.opt) {
315ba081e43SBrian Somers     next = ccp->out.opt->next;
316ba081e43SBrian Somers     free(ccp->out.opt);
317ba081e43SBrian Somers     ccp->out.opt = next;
318ba081e43SBrian Somers   }
3191ae349f5Scvs2svn }
3201ae349f5Scvs2svn 
3211ae349f5Scvs2svn static void
3221ae349f5Scvs2svn CcpLayerDown(struct fsm *fp)
3231ae349f5Scvs2svn {
3247308ec68SBrian Somers   /* About to come down */
325d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerDown.\n", fp->link->name);
3261ae349f5Scvs2svn }
3271ae349f5Scvs2svn 
3281ae349f5Scvs2svn /*
3291ae349f5Scvs2svn  *  Called when CCP has reached the OPEN state
3301ae349f5Scvs2svn  */
3311ae349f5Scvs2svn static void
3321ae349f5Scvs2svn CcpLayerUp(struct fsm *fp)
3331ae349f5Scvs2svn {
3347308ec68SBrian Somers   /* We're now up */
335aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
336d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerUp.\n", fp->link->name);
33703036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
33803036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
33903036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
34003036ec7SBrian Somers     if (ccp->in.state == NULL) {
341d47dceb8SBrian Somers       LogPrintf(LogERROR, "%s: %s (in) initialisation failure\n",
342d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
34383d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
344247ab36dSBrian Somers       FsmClose(fp);
345247ab36dSBrian Somers     }
34603036ec7SBrian Somers   }
34703036ec7SBrian Somers 
34803036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
34903036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
35003036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
35103036ec7SBrian Somers                        (&ccp->out.opt->val);
35203036ec7SBrian Somers     if (ccp->out.state == NULL) {
353d47dceb8SBrian Somers       LogPrintf(LogERROR, "%s: %s (out) initialisation failure\n",
354d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
35583d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
356247ab36dSBrian Somers       FsmClose(fp);
357247ab36dSBrian Somers     }
35803036ec7SBrian Somers   }
35903036ec7SBrian Somers 
360d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
361d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
36283d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
3631ae349f5Scvs2svn }
3641ae349f5Scvs2svn 
3651ae349f5Scvs2svn static void
36630c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
36730c2f2ffSBrian Somers                 struct fsm_decode *dec)
3681ae349f5Scvs2svn {
3697308ec68SBrian Somers   /* Deal with incoming data */
370aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3711ae349f5Scvs2svn   int type, length;
3721ae349f5Scvs2svn   int f;
37303036ec7SBrian Somers   const char *end;
3741ae349f5Scvs2svn 
3751ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
3761ae349f5Scvs2svn     type = *cp;
3771ae349f5Scvs2svn     length = cp[1];
37803036ec7SBrian Somers 
379d47dceb8SBrian Somers     if (length == 0) {
380d47dceb8SBrian Somers       LogPrintf(LogCCP, "%s: CCP size zero\n", fp->link->name);
381d47dceb8SBrian Somers       break;
382d47dceb8SBrian Somers     }
383d47dceb8SBrian Somers 
38403036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
38503036ec7SBrian Somers       length = sizeof(struct lcp_opt);
386d47dceb8SBrian Somers       LogPrintf(LogCCP, "%s: Warning: Truncating length to %d\n",
387d47dceb8SBrian Somers                 fp->link->name, length);
38803036ec7SBrian Somers     }
3891ae349f5Scvs2svn 
3901ae349f5Scvs2svn     for (f = NALGORITHMS-1; f > -1; f--)
3911ae349f5Scvs2svn       if (algorithm[f]->id == type)
3921ae349f5Scvs2svn         break;
3931ae349f5Scvs2svn 
39403036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
39503036ec7SBrian Somers     if (end == NULL)
39603036ec7SBrian Somers       end = "";
39703036ec7SBrian Somers 
39803036ec7SBrian Somers     if (type < NCFTYPES)
39903036ec7SBrian Somers       LogPrintf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
40003036ec7SBrian Somers     else
40103036ec7SBrian Somers       LogPrintf(LogCCP, " ???[%d] %s\n", length, end);
40203036ec7SBrian Somers 
4031ae349f5Scvs2svn     if (f == -1) {
4041ae349f5Scvs2svn       /* Don't understand that :-( */
4051ae349f5Scvs2svn       if (mode_type == MODE_REQ) {
40683d1af55SBrian Somers         ccp->my_reject |= (1 << type);
40730c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
40830c2f2ffSBrian Somers         dec->rejend += length;
4091ae349f5Scvs2svn       }
4101ae349f5Scvs2svn     } else {
41103036ec7SBrian Somers       struct ccp_opt *o;
4121ae349f5Scvs2svn 
4131ae349f5Scvs2svn       switch (mode_type) {
4141ae349f5Scvs2svn       case MODE_REQ:
4151342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
4161342caedSBrian Somers             ccp->in.algorithm == -1) {
41703036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
41803036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4191ae349f5Scvs2svn           case MODE_REJ:
42003036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
42103036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4221ae349f5Scvs2svn             break;
4231ae349f5Scvs2svn           case MODE_NAK:
42403036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
42503036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4261ae349f5Scvs2svn             break;
4271ae349f5Scvs2svn           case MODE_ACK:
42830c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
42930c2f2ffSBrian Somers 	    dec->ackend += length;
43083d1af55SBrian Somers 	    ccp->his_proto = type;
43103036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4321ae349f5Scvs2svn             break;
4331ae349f5Scvs2svn           }
4341ae349f5Scvs2svn 	} else {
43530c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
43630c2f2ffSBrian Somers 	  dec->rejend += length;
4371ae349f5Scvs2svn 	}
4381ae349f5Scvs2svn 	break;
4391ae349f5Scvs2svn       case MODE_NAK:
44003036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
44103036ec7SBrian Somers           if (o->val.id == cp[0])
44203036ec7SBrian Somers             break;
44303036ec7SBrian Somers         if (o == NULL)
444d47dceb8SBrian Somers           LogPrintf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n",
445d47dceb8SBrian Somers                     fp->link->name);
44603036ec7SBrian Somers         else {
44703036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
44803036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
44983d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4501ae349f5Scvs2svn           else {
45183d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
45283d1af55SBrian Somers 	    ccp->my_proto = -1;
4531ae349f5Scvs2svn           }
45403036ec7SBrian Somers         }
4551ae349f5Scvs2svn         break;
4561ae349f5Scvs2svn       case MODE_REJ:
45783d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
45883d1af55SBrian Somers 	ccp->my_proto = -1;
4591ae349f5Scvs2svn 	break;
4601ae349f5Scvs2svn       }
4611ae349f5Scvs2svn     }
4621ae349f5Scvs2svn 
46303036ec7SBrian Somers     plen -= cp[1];
46403036ec7SBrian Somers     cp += cp[1];
4651ae349f5Scvs2svn   }
4661ae349f5Scvs2svn 
467e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
4681342caedSBrian Somers     if (dec->rejend != dec->rej) {
46903036ec7SBrian Somers       /* rejects are preferred */
47003036ec7SBrian Somers       dec->ackend = dec->ack;
47103036ec7SBrian Somers       dec->nakend = dec->nak;
47203036ec7SBrian Somers       if (ccp->in.state == NULL) {
47383d1af55SBrian Somers         ccp->his_proto = -1;
47403036ec7SBrian Somers         ccp->in.algorithm = -1;
47503036ec7SBrian Somers       }
4761342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
47703036ec7SBrian Somers       /* then NAKs */
47803036ec7SBrian Somers       dec->ackend = dec->ack;
47903036ec7SBrian Somers       if (ccp->in.state == NULL) {
48003036ec7SBrian Somers         ccp->his_proto = -1;
48103036ec7SBrian Somers         ccp->in.algorithm = -1;
482247ab36dSBrian Somers       }
4831ae349f5Scvs2svn     }
4841ae349f5Scvs2svn   }
485e43ebac1SBrian Somers }
4861ae349f5Scvs2svn 
4871ae349f5Scvs2svn void
488f4768038SBrian Somers CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
4891ae349f5Scvs2svn {
4907308ec68SBrian Somers   /* Got PROTO_CCP from link */
491455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
492f4768038SBrian Somers     FsmInput(&ccp->fsm, bp);
493455aabc3SBrian Somers   else if (bundle_Phase(bundle) < PHASE_NETWORK) {
494d47dceb8SBrian Somers     LogPrintf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
495d47dceb8SBrian Somers               ccp->fsm.link->name, bundle_PhaseName(bundle));
4961ae349f5Scvs2svn     pfree(bp);
4971ae349f5Scvs2svn   }
4981ae349f5Scvs2svn }
4991ae349f5Scvs2svn 
500503a7782SBrian Somers static void
501503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5021ae349f5Scvs2svn {
5037308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
504f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
505f4768038SBrian Somers 
506f4768038SBrian Somers   if (ccp->reset_sent != -1) {
507f4768038SBrian Somers     if (id != ccp->reset_sent) {
508d47dceb8SBrian Somers       LogPrintf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)"
509d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
5101ae349f5Scvs2svn       return;
5111ae349f5Scvs2svn     }
5121ae349f5Scvs2svn     /* Whaddaya know - a correct reset ack */
513f4768038SBrian Somers   } else if (id == ccp->last_reset)
514d47dceb8SBrian Somers     LogPrintf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
515d47dceb8SBrian Somers               fp->link->name);
5161ae349f5Scvs2svn   else {
517d47dceb8SBrian Somers     LogPrintf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n",
518d47dceb8SBrian Somers               fp->link->name, id);
5191ae349f5Scvs2svn     return;
5201ae349f5Scvs2svn   }
5211ae349f5Scvs2svn 
522f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
523f4768038SBrian Somers   ccp->reset_sent = -1;
52403036ec7SBrian Somers   if (ccp->in.state != NULL)
52503036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5261ae349f5Scvs2svn }
5271ae349f5Scvs2svn 
5281ae349f5Scvs2svn int
5293b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
530503a7782SBrian Somers              struct mbuf *m)
5311ae349f5Scvs2svn {
532503a7782SBrian Somers   /* Compress outgoing Network Layer data */
53303036ec7SBrian Somers   if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED &&
53403036ec7SBrian Somers       ccp->out.state != NULL)
53503036ec7SBrian Somers     return (*algorithm[ccp->out.algorithm]->o.Write)
53603036ec7SBrian Somers              (ccp->out.state, ccp, l, pri, proto, m);
5371ae349f5Scvs2svn   return 0;
5381ae349f5Scvs2svn }
5391ae349f5Scvs2svn 
5401ae349f5Scvs2svn struct mbuf *
541503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
5421ae349f5Scvs2svn {
543ee6c193fSBrian Somers   /*
544ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
545ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
546ee6c193fSBrian Somers    */
547e43ebac1SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
548ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
5497308ec68SBrian Somers       /* Decompress incoming data */
5502267893fSBrian Somers       if (ccp->reset_sent != -1)
5511ae349f5Scvs2svn         /* Send another REQ and put the packet in the bit bucket */
552503a7782SBrian Somers         FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
5532267893fSBrian Somers       else if (ccp->in.state != NULL)
55403036ec7SBrian Somers         return (*algorithm[ccp->in.algorithm]->i.Read)
55503036ec7SBrian Somers                  (ccp->in.state, ccp, proto, bp);
556ee6c193fSBrian Somers       pfree(bp);
557ee6c193fSBrian Somers       bp = NULL;
55803036ec7SBrian Somers     } else if ((*proto & 0xfff1) == 0x21 && ccp->in.state != NULL)
559ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
56003036ec7SBrian Somers       (*algorithm[ccp->in.algorithm]->i.DictSetup)
56103036ec7SBrian Somers         (ccp->in.state, ccp, *proto, bp);
562e43ebac1SBrian Somers   }
5631ae349f5Scvs2svn 
564ee6c193fSBrian Somers   return bp;
5651ae349f5Scvs2svn }
566ed32233cSBrian Somers 
567ed32233cSBrian Somers u_short
568ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
569ed32233cSBrian Somers {
570ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
571ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
572ed32233cSBrian Somers }
573