xref: /freebsd/usr.sbin/ppp/ccp.c (revision e43ebac1c2549c8a15714101e558db3e2007e0e6)
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  *
20e43ebac1SBrian Somers  * $Id: ccp.c,v 1.30.2.38 1998/04/24 19:15:36 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>
291ae349f5Scvs2svn 
301ae349f5Scvs2svn #include <stdio.h>
3103036ec7SBrian Somers #include <stdlib.h>
3285b542cfSBrian Somers #include <termios.h>
331ae349f5Scvs2svn 
341ae349f5Scvs2svn #include "command.h"
351ae349f5Scvs2svn #include "mbuf.h"
361ae349f5Scvs2svn #include "log.h"
371ae349f5Scvs2svn #include "defs.h"
381ae349f5Scvs2svn #include "timer.h"
391ae349f5Scvs2svn #include "fsm.h"
401ae349f5Scvs2svn #include "lcpproto.h"
411ae349f5Scvs2svn #include "lcp.h"
421ae349f5Scvs2svn #include "ccp.h"
431ae349f5Scvs2svn #include "pred.h"
441ae349f5Scvs2svn #include "deflate.h"
455828db6dSBrian Somers #include "throughput.h"
465828db6dSBrian Somers #include "iplist.h"
47eaa4df37SBrian Somers #include "slcompress.h"
485828db6dSBrian Somers #include "ipcp.h"
495ca5389aSBrian Somers #include "filter.h"
5085b542cfSBrian Somers #include "descriptor.h"
5185b542cfSBrian Somers #include "prompt.h"
52879ed6faSBrian Somers #include "lqr.h"
53503a7782SBrian Somers #include "hdlc.h"
54503a7782SBrian Somers #include "link.h"
553b0f8d2eSBrian Somers #include "mp.h"
56ed32233cSBrian Somers #include "async.h"
57ed32233cSBrian Somers #include "physical.h"
583b0f8d2eSBrian Somers #include "bundle.h"
591ae349f5Scvs2svn 
601ae349f5Scvs2svn static void CcpSendConfigReq(struct fsm *);
612267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
622267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
6330c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
6430c2f2ffSBrian Somers                             struct fsm_decode *);
651ae349f5Scvs2svn static void CcpLayerStart(struct fsm *);
661ae349f5Scvs2svn static void CcpLayerFinish(struct fsm *);
671ae349f5Scvs2svn static void CcpLayerUp(struct fsm *);
681ae349f5Scvs2svn static void CcpLayerDown(struct fsm *);
691ae349f5Scvs2svn static void CcpInitRestartCounter(struct fsm *);
70503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
71503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
721ae349f5Scvs2svn 
7383d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
7483d1af55SBrian Somers   CcpLayerUp,
7583d1af55SBrian Somers   CcpLayerDown,
7683d1af55SBrian Somers   CcpLayerStart,
776d666775SBrian Somers   CcpLayerFinish,
7883d1af55SBrian Somers   CcpInitRestartCounter,
7983d1af55SBrian Somers   CcpSendConfigReq,
802267893fSBrian Somers   CcpSentTerminateReq,
8183d1af55SBrian Somers   CcpSendTerminateAck,
82503a7782SBrian Somers   CcpDecodeConfig,
83503a7782SBrian Somers   CcpRecvResetReq,
84503a7782SBrian Somers   CcpRecvResetAck
8583d1af55SBrian Somers };
8683d1af55SBrian Somers 
871ae349f5Scvs2svn static char const *cftypes[] = {
881ae349f5Scvs2svn   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
891ae349f5Scvs2svn   "OUI",		/* 0: OUI */
901ae349f5Scvs2svn   "PRED1",		/* 1: Predictor type 1 */
911ae349f5Scvs2svn   "PRED2",		/* 2: Predictor type 2 */
921ae349f5Scvs2svn   "PUDDLE",		/* 3: Puddle Jumber */
931ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
941ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
951ae349f5Scvs2svn   "HWPPC",		/* 16: Hewlett-Packard PPC */
961ae349f5Scvs2svn   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
978f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
981ae349f5Scvs2svn   "GAND",		/* 19: Gandalf FZA (rfc1993) */
991ae349f5Scvs2svn   "V42BIS",		/* 20: ARG->DATA.42bis compression */
1001ae349f5Scvs2svn   "BSD",		/* 21: BSD LZW Compress */
1011ae349f5Scvs2svn   "???",
1021ae349f5Scvs2svn   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1031ae349f5Scvs2svn   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1041342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1051ae349f5Scvs2svn   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1061ae349f5Scvs2svn   "DEFLATE",		/* 26: Deflate (rfc1979) */
1071ae349f5Scvs2svn };
1081ae349f5Scvs2svn 
1091ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1101ae349f5Scvs2svn 
1111ae349f5Scvs2svn static const char *
1121ae349f5Scvs2svn protoname(int proto)
1131ae349f5Scvs2svn {
1141ae349f5Scvs2svn   if (proto < 0 || proto > NCFTYPES)
1151ae349f5Scvs2svn     return "none";
1161ae349f5Scvs2svn   return cftypes[proto];
1171ae349f5Scvs2svn }
1181ae349f5Scvs2svn 
1191ae349f5Scvs2svn /* We support these algorithms, and Req them in the given order */
1201ae349f5Scvs2svn static const struct ccp_algorithm *algorithm[] = {
1211ae349f5Scvs2svn   &DeflateAlgorithm,
1221ae349f5Scvs2svn   &Pred1Algorithm,
1231ae349f5Scvs2svn   &PppdDeflateAlgorithm
1241ae349f5Scvs2svn };
1251ae349f5Scvs2svn 
1261ae349f5Scvs2svn #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1271ae349f5Scvs2svn 
1281ae349f5Scvs2svn int
129503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
1301ae349f5Scvs2svn {
131cd9647a1SBrian Somers   struct link *l = ChooseLink(arg);
132cd9647a1SBrian Somers   struct ccp *ccp = &l->ccp;
133503a7782SBrian Somers 
134b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1351e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
136b6217683SBrian Somers   prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
137503a7782SBrian Somers                 protoname(ccp->my_proto), protoname(ccp->his_proto));
138b6217683SBrian Somers   prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
139503a7782SBrian Somers                 ccp->uncompout, ccp->compout,
140503a7782SBrian Somers                 ccp->compin, ccp->uncompin);
141cd9647a1SBrian Somers 
142b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
1431342caedSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry);
144b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
145b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
146b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1471342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1481342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1491342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1501342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1511342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1521342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
1531ae349f5Scvs2svn   return 0;
1541ae349f5Scvs2svn }
1551ae349f5Scvs2svn 
1561ae349f5Scvs2svn void
1576d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1586d666775SBrian Somers          const struct fsm_parent *parent)
1591ae349f5Scvs2svn {
1607308ec68SBrian Somers   /* Initialise ourselves */
1613b0f8d2eSBrian Somers   static const char *timer_names[] =
1623b0f8d2eSBrian Somers     {"CCP restart", "CCP openmode", "CCP stopped"};
1633b0f8d2eSBrian Somers 
1643b0f8d2eSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
1653b0f8d2eSBrian Somers            bundle, l, parent, &ccp_Callbacks, timer_names);
166cd9647a1SBrian Somers 
16703036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
16803036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
169cd9647a1SBrian Somers   ccp->cfg.fsmretry = DEF_FSMRETRY;
1701342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
1711342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
1721342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
173cd9647a1SBrian Somers 
174503a7782SBrian Somers   ccp_Setup(ccp);
175503a7782SBrian Somers }
176503a7782SBrian Somers 
177503a7782SBrian Somers void
178503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
179503a7782SBrian Somers {
180503a7782SBrian Somers   /* Set ourselves up for a startup */
181503a7782SBrian Somers   ccp->fsm.open_mode = 0;
1825454ccd9SBrian Somers   ccp->fsm.maxconfig = 10;
183503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
184503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
18503036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
18603036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
18703036ec7SBrian Somers   ccp->in.opt.id = -1;
18803036ec7SBrian Somers   ccp->out.opt = NULL;
189503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
190503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
191503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
1921ae349f5Scvs2svn }
1931ae349f5Scvs2svn 
1941ae349f5Scvs2svn static void
1951ae349f5Scvs2svn CcpInitRestartCounter(struct fsm *fp)
1961ae349f5Scvs2svn {
1977308ec68SBrian Somers   /* Set fsm timer load */
198cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
199cd9647a1SBrian Somers 
200cd9647a1SBrian Somers   fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS;
2011ae349f5Scvs2svn   fp->restart = 5;
2021ae349f5Scvs2svn }
2031ae349f5Scvs2svn 
2041ae349f5Scvs2svn static void
2051ae349f5Scvs2svn CcpSendConfigReq(struct fsm *fp)
2061ae349f5Scvs2svn {
2077308ec68SBrian Somers   /* Send config REQ please */
208aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
20903036ec7SBrian Somers   struct ccp_opt **o;
21030c2f2ffSBrian Somers   u_char *cp, buff[100];
21103036ec7SBrian Somers   int f, alloc;
2121ae349f5Scvs2svn 
21330c2f2ffSBrian Somers   cp = buff;
21403036ec7SBrian Somers   o = &ccp->out.opt;
21503036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
21683d1af55SBrian Somers   ccp->my_proto = -1;
21703036ec7SBrian Somers   ccp->out.algorithm = -1;
2181ae349f5Scvs2svn   for (f = 0; f < NALGORITHMS; f++)
2191342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2201342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
221ba081e43SBrian Somers 
222ba081e43SBrian Somers       if (!alloc)
223ba081e43SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
224ba081e43SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
225ba081e43SBrian Somers             break;
226ba081e43SBrian Somers 
227ba081e43SBrian Somers       if (alloc || *o == NULL) {
22803036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
22903036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
23003036ec7SBrian Somers         (*o)->val.len = 2;
23103036ec7SBrian Somers         (*o)->next = NULL;
23203036ec7SBrian Somers         (*o)->algorithm = f;
23303036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
23403036ec7SBrian Somers       }
2351ae349f5Scvs2svn 
23603036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
237d47dceb8SBrian Somers         LogPrintf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
23830c2f2ffSBrian Somers         break;
23930c2f2ffSBrian Somers       }
2402267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2412267893fSBrian Somers       cp += (*o)->val.len;
24203036ec7SBrian Somers 
24303036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
24403036ec7SBrian Somers       ccp->out.algorithm = f;
24503036ec7SBrian Somers 
24603036ec7SBrian Somers       if (alloc)
24703036ec7SBrian Somers         o = &(*o)->next;
2481ae349f5Scvs2svn     }
2492267893fSBrian Somers 
2502267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff);
2511ae349f5Scvs2svn }
2521ae349f5Scvs2svn 
2531ae349f5Scvs2svn void
2541ae349f5Scvs2svn CcpSendResetReq(struct fsm *fp)
2551ae349f5Scvs2svn {
2567308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
257aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2582267893fSBrian Somers 
25983d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
26083d1af55SBrian Somers   ccp->last_reset = -1;
2611ae349f5Scvs2svn   FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
2621ae349f5Scvs2svn }
2631ae349f5Scvs2svn 
2641ae349f5Scvs2svn static void
2652267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
2661ae349f5Scvs2svn {
2677308ec68SBrian Somers   /* Term REQ just sent by FSM */
2681ae349f5Scvs2svn }
2691ae349f5Scvs2svn 
2701ae349f5Scvs2svn static void
2712267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
2721ae349f5Scvs2svn {
2737308ec68SBrian Somers   /* Send Term ACK please */
2742267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
2751ae349f5Scvs2svn }
2761ae349f5Scvs2svn 
277503a7782SBrian Somers static void
2781ae349f5Scvs2svn CcpRecvResetReq(struct fsm *fp)
2791ae349f5Scvs2svn {
2807308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
281aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
28203036ec7SBrian Somers   if (ccp->out.state != NULL)
28303036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
2841ae349f5Scvs2svn }
2851ae349f5Scvs2svn 
2861ae349f5Scvs2svn static void
2871ae349f5Scvs2svn CcpLayerStart(struct fsm *fp)
2881ae349f5Scvs2svn {
2897308ec68SBrian Somers   /* We're about to start up ! */
290d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerStart.\n", fp->link->name);
2911ae349f5Scvs2svn }
2921ae349f5Scvs2svn 
2931ae349f5Scvs2svn static void
2941ae349f5Scvs2svn CcpLayerFinish(struct fsm *fp)
2951ae349f5Scvs2svn {
2967308ec68SBrian Somers   /* We're now down */
297aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
298ba081e43SBrian Somers   struct ccp_opt *next;
299ba081e43SBrian Somers 
300d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerFinish.\n", fp->link->name);
30103036ec7SBrian Somers   if (ccp->in.state != NULL) {
30203036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
30303036ec7SBrian Somers     ccp->in.state = NULL;
3048d9b9867SBrian Somers     ccp->in.algorithm = -1;
3057308ec68SBrian Somers   }
30603036ec7SBrian Somers   if (ccp->out.state != NULL) {
30703036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
30803036ec7SBrian Somers     ccp->out.state = NULL;
3098d9b9867SBrian Somers     ccp->out.algorithm = -1;
3107308ec68SBrian Somers   }
3118d9b9867SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
312ba081e43SBrian Somers 
313ba081e43SBrian Somers   while (ccp->out.opt) {
314ba081e43SBrian Somers     next = ccp->out.opt->next;
315ba081e43SBrian Somers     free(ccp->out.opt);
316ba081e43SBrian Somers     ccp->out.opt = next;
317ba081e43SBrian Somers   }
3181ae349f5Scvs2svn }
3191ae349f5Scvs2svn 
3201ae349f5Scvs2svn static void
3211ae349f5Scvs2svn CcpLayerDown(struct fsm *fp)
3221ae349f5Scvs2svn {
3237308ec68SBrian Somers   /* About to come down */
324d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerDown.\n", fp->link->name);
3251ae349f5Scvs2svn }
3261ae349f5Scvs2svn 
3271ae349f5Scvs2svn /*
3281ae349f5Scvs2svn  *  Called when CCP has reached the OPEN state
3291ae349f5Scvs2svn  */
3301ae349f5Scvs2svn static void
3311ae349f5Scvs2svn CcpLayerUp(struct fsm *fp)
3321ae349f5Scvs2svn {
3337308ec68SBrian Somers   /* We're now up */
334aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
335d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: CcpLayerUp.\n", fp->link->name);
33603036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
33703036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
33803036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
33903036ec7SBrian Somers     if (ccp->in.state == NULL) {
340d47dceb8SBrian Somers       LogPrintf(LogERROR, "%s: %s (in) initialisation failure\n",
341d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->his_proto));
34283d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
343247ab36dSBrian Somers       FsmClose(fp);
344247ab36dSBrian Somers     }
34503036ec7SBrian Somers   }
34603036ec7SBrian Somers 
34703036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
34803036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
34903036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
35003036ec7SBrian Somers                        (&ccp->out.opt->val);
35103036ec7SBrian Somers     if (ccp->out.state == NULL) {
352d47dceb8SBrian Somers       LogPrintf(LogERROR, "%s: %s (out) initialisation failure\n",
353d47dceb8SBrian Somers                 fp->link->name, protoname(ccp->my_proto));
35483d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
355247ab36dSBrian Somers       FsmClose(fp);
356247ab36dSBrian Somers     }
35703036ec7SBrian Somers   }
35803036ec7SBrian Somers 
359d47dceb8SBrian Somers   LogPrintf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
360d47dceb8SBrian Somers             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
36183d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
3621ae349f5Scvs2svn }
3631ae349f5Scvs2svn 
3641ae349f5Scvs2svn static void
36530c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
36630c2f2ffSBrian Somers                 struct fsm_decode *dec)
3671ae349f5Scvs2svn {
3687308ec68SBrian Somers   /* Deal with incoming data */
369aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3701ae349f5Scvs2svn   int type, length;
3711ae349f5Scvs2svn   int f;
37203036ec7SBrian Somers   const char *end;
3731ae349f5Scvs2svn 
3741ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
3751ae349f5Scvs2svn     type = *cp;
3761ae349f5Scvs2svn     length = cp[1];
37703036ec7SBrian Somers 
378d47dceb8SBrian Somers     if (length == 0) {
379d47dceb8SBrian Somers       LogPrintf(LogCCP, "%s: CCP size zero\n", fp->link->name);
380d47dceb8SBrian Somers       break;
381d47dceb8SBrian Somers     }
382d47dceb8SBrian Somers 
38303036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
38403036ec7SBrian Somers       length = sizeof(struct lcp_opt);
385d47dceb8SBrian Somers       LogPrintf(LogCCP, "%s: Warning: Truncating length to %d\n",
386d47dceb8SBrian Somers                 fp->link->name, length);
38703036ec7SBrian Somers     }
3881ae349f5Scvs2svn 
3891ae349f5Scvs2svn     for (f = NALGORITHMS-1; f > -1; f--)
3901ae349f5Scvs2svn       if (algorithm[f]->id == type)
3911ae349f5Scvs2svn         break;
3921ae349f5Scvs2svn 
39303036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
39403036ec7SBrian Somers     if (end == NULL)
39503036ec7SBrian Somers       end = "";
39603036ec7SBrian Somers 
39703036ec7SBrian Somers     if (type < NCFTYPES)
39803036ec7SBrian Somers       LogPrintf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
39903036ec7SBrian Somers     else
40003036ec7SBrian Somers       LogPrintf(LogCCP, " ???[%d] %s\n", length, end);
40103036ec7SBrian Somers 
4021ae349f5Scvs2svn     if (f == -1) {
4031ae349f5Scvs2svn       /* Don't understand that :-( */
4041ae349f5Scvs2svn       if (mode_type == MODE_REQ) {
40583d1af55SBrian Somers         ccp->my_reject |= (1 << type);
40630c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
40730c2f2ffSBrian Somers         dec->rejend += length;
4081ae349f5Scvs2svn       }
4091ae349f5Scvs2svn     } else {
41003036ec7SBrian Somers       struct ccp_opt *o;
4111ae349f5Scvs2svn 
4121ae349f5Scvs2svn       switch (mode_type) {
4131ae349f5Scvs2svn       case MODE_REQ:
4141342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
4151342caedSBrian Somers             ccp->in.algorithm == -1) {
41603036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
41703036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4181ae349f5Scvs2svn           case MODE_REJ:
41903036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
42003036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4211ae349f5Scvs2svn             break;
4221ae349f5Scvs2svn           case MODE_NAK:
42303036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
42403036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4251ae349f5Scvs2svn             break;
4261ae349f5Scvs2svn           case MODE_ACK:
42730c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
42830c2f2ffSBrian Somers 	    dec->ackend += length;
42983d1af55SBrian Somers 	    ccp->his_proto = type;
43003036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4311ae349f5Scvs2svn             break;
4321ae349f5Scvs2svn           }
4331ae349f5Scvs2svn 	} else {
43430c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
43530c2f2ffSBrian Somers 	  dec->rejend += length;
4361ae349f5Scvs2svn 	}
4371ae349f5Scvs2svn 	break;
4381ae349f5Scvs2svn       case MODE_NAK:
43903036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
44003036ec7SBrian Somers           if (o->val.id == cp[0])
44103036ec7SBrian Somers             break;
44203036ec7SBrian Somers         if (o == NULL)
443d47dceb8SBrian Somers           LogPrintf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n",
444d47dceb8SBrian Somers                     fp->link->name);
44503036ec7SBrian Somers         else {
44603036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
44703036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
44883d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4491ae349f5Scvs2svn           else {
45083d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
45183d1af55SBrian Somers 	    ccp->my_proto = -1;
4521ae349f5Scvs2svn           }
45303036ec7SBrian Somers         }
4541ae349f5Scvs2svn         break;
4551ae349f5Scvs2svn       case MODE_REJ:
45683d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
45783d1af55SBrian Somers 	ccp->my_proto = -1;
4581ae349f5Scvs2svn 	break;
4591ae349f5Scvs2svn       }
4601ae349f5Scvs2svn     }
4611ae349f5Scvs2svn 
46203036ec7SBrian Somers     plen -= cp[1];
46303036ec7SBrian Somers     cp += cp[1];
4641ae349f5Scvs2svn   }
4651ae349f5Scvs2svn 
466e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
4671342caedSBrian Somers     if (dec->rejend != dec->rej) {
46803036ec7SBrian Somers       /* rejects are preferred */
46903036ec7SBrian Somers       dec->ackend = dec->ack;
47003036ec7SBrian Somers       dec->nakend = dec->nak;
47103036ec7SBrian Somers       if (ccp->in.state == NULL) {
47283d1af55SBrian Somers         ccp->his_proto = -1;
47303036ec7SBrian Somers         ccp->in.algorithm = -1;
47403036ec7SBrian Somers       }
4751342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
47603036ec7SBrian Somers       /* then NAKs */
47703036ec7SBrian Somers       dec->ackend = dec->ack;
47803036ec7SBrian Somers       if (ccp->in.state == NULL) {
47903036ec7SBrian Somers         ccp->his_proto = -1;
48003036ec7SBrian Somers         ccp->in.algorithm = -1;
481247ab36dSBrian Somers       }
4821ae349f5Scvs2svn     }
4831ae349f5Scvs2svn   }
484e43ebac1SBrian Somers }
4851ae349f5Scvs2svn 
4861ae349f5Scvs2svn void
487f4768038SBrian Somers CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
4881ae349f5Scvs2svn {
4897308ec68SBrian Somers   /* Got PROTO_CCP from link */
490455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
491f4768038SBrian Somers     FsmInput(&ccp->fsm, bp);
492455aabc3SBrian Somers   else if (bundle_Phase(bundle) < PHASE_NETWORK) {
493d47dceb8SBrian Somers     LogPrintf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
494d47dceb8SBrian Somers               ccp->fsm.link->name, bundle_PhaseName(bundle));
4951ae349f5Scvs2svn     pfree(bp);
4961ae349f5Scvs2svn   }
4971ae349f5Scvs2svn }
4981ae349f5Scvs2svn 
499503a7782SBrian Somers static void
500503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
5011ae349f5Scvs2svn {
5027308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
503f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
504f4768038SBrian Somers 
505f4768038SBrian Somers   if (ccp->reset_sent != -1) {
506f4768038SBrian Somers     if (id != ccp->reset_sent) {
507d47dceb8SBrian Somers       LogPrintf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)"
508d47dceb8SBrian Somers                 " ignored\n", fp->link->name, id, ccp->reset_sent);
5091ae349f5Scvs2svn       return;
5101ae349f5Scvs2svn     }
5111ae349f5Scvs2svn     /* Whaddaya know - a correct reset ack */
512f4768038SBrian Somers   } else if (id == ccp->last_reset)
513d47dceb8SBrian Somers     LogPrintf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
514d47dceb8SBrian Somers               fp->link->name);
5151ae349f5Scvs2svn   else {
516d47dceb8SBrian Somers     LogPrintf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n",
517d47dceb8SBrian Somers               fp->link->name, id);
5181ae349f5Scvs2svn     return;
5191ae349f5Scvs2svn   }
5201ae349f5Scvs2svn 
521f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
522f4768038SBrian Somers   ccp->reset_sent = -1;
52303036ec7SBrian Somers   if (ccp->in.state != NULL)
52403036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5251ae349f5Scvs2svn }
5261ae349f5Scvs2svn 
5271ae349f5Scvs2svn int
5283b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
529503a7782SBrian Somers              struct mbuf *m)
5301ae349f5Scvs2svn {
531503a7782SBrian Somers   /* Compress outgoing Network Layer data */
53203036ec7SBrian Somers   if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED &&
53303036ec7SBrian Somers       ccp->out.state != NULL)
53403036ec7SBrian Somers     return (*algorithm[ccp->out.algorithm]->o.Write)
53503036ec7SBrian Somers              (ccp->out.state, ccp, l, pri, proto, m);
5361ae349f5Scvs2svn   return 0;
5371ae349f5Scvs2svn }
5381ae349f5Scvs2svn 
5391ae349f5Scvs2svn struct mbuf *
540503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
5411ae349f5Scvs2svn {
542ee6c193fSBrian Somers   /*
543ed32233cSBrian Somers    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
544ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
545ee6c193fSBrian Somers    */
546e43ebac1SBrian Somers   if (ccp->fsm.state == ST_OPENED) {
547ed32233cSBrian Somers     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
5487308ec68SBrian Somers       /* Decompress incoming data */
5492267893fSBrian Somers       if (ccp->reset_sent != -1)
5501ae349f5Scvs2svn         /* Send another REQ and put the packet in the bit bucket */
551503a7782SBrian Somers         FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
5522267893fSBrian Somers       else if (ccp->in.state != NULL)
55303036ec7SBrian Somers         return (*algorithm[ccp->in.algorithm]->i.Read)
55403036ec7SBrian Somers                  (ccp->in.state, ccp, proto, bp);
555ee6c193fSBrian Somers       pfree(bp);
556ee6c193fSBrian Somers       bp = NULL;
55703036ec7SBrian Somers     } else if ((*proto & 0xfff1) == 0x21 && ccp->in.state != NULL)
558ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
55903036ec7SBrian Somers       (*algorithm[ccp->in.algorithm]->i.DictSetup)
56003036ec7SBrian Somers         (ccp->in.state, ccp, *proto, bp);
561e43ebac1SBrian Somers   }
5621ae349f5Scvs2svn 
563ee6c193fSBrian Somers   return bp;
5641ae349f5Scvs2svn }
565ed32233cSBrian Somers 
566ed32233cSBrian Somers u_short
567ed32233cSBrian Somers ccp_Proto(struct ccp *ccp)
568ed32233cSBrian Somers {
569ed32233cSBrian Somers   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
570ed32233cSBrian Somers          PROTO_COMPD : PROTO_ICOMPD;
571ed32233cSBrian Somers }
572