xref: /freebsd/usr.sbin/ppp/ccp.c (revision 1342caed9c9c94c4524363408e77113333963bd5)
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  *
201342caedSBrian Somers  * $Id: ccp.c,v 1.30.2.33 1998/04/07 00:53:22 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"
563b0f8d2eSBrian Somers #include "bundle.h"
571ae349f5Scvs2svn 
581ae349f5Scvs2svn static void CcpSendConfigReq(struct fsm *);
592267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
602267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
6130c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
6230c2f2ffSBrian Somers                             struct fsm_decode *);
631ae349f5Scvs2svn static void CcpLayerStart(struct fsm *);
641ae349f5Scvs2svn static void CcpLayerFinish(struct fsm *);
651ae349f5Scvs2svn static void CcpLayerUp(struct fsm *);
661ae349f5Scvs2svn static void CcpLayerDown(struct fsm *);
671ae349f5Scvs2svn static void CcpInitRestartCounter(struct fsm *);
68503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
69503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
701ae349f5Scvs2svn 
7183d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
7283d1af55SBrian Somers   CcpLayerUp,
7383d1af55SBrian Somers   CcpLayerDown,
7483d1af55SBrian Somers   CcpLayerStart,
756d666775SBrian Somers   CcpLayerFinish,
7683d1af55SBrian Somers   CcpInitRestartCounter,
7783d1af55SBrian Somers   CcpSendConfigReq,
782267893fSBrian Somers   CcpSentTerminateReq,
7983d1af55SBrian Somers   CcpSendTerminateAck,
80503a7782SBrian Somers   CcpDecodeConfig,
81503a7782SBrian Somers   CcpRecvResetReq,
82503a7782SBrian Somers   CcpRecvResetAck
8383d1af55SBrian Somers };
8483d1af55SBrian Somers 
851ae349f5Scvs2svn static char const *cftypes[] = {
861ae349f5Scvs2svn   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
871ae349f5Scvs2svn   "OUI",		/* 0: OUI */
881ae349f5Scvs2svn   "PRED1",		/* 1: Predictor type 1 */
891ae349f5Scvs2svn   "PRED2",		/* 2: Predictor type 2 */
901ae349f5Scvs2svn   "PUDDLE",		/* 3: Puddle Jumber */
911ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
921ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
931ae349f5Scvs2svn   "HWPPC",		/* 16: Hewlett-Packard PPC */
941ae349f5Scvs2svn   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
958f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
961ae349f5Scvs2svn   "GAND",		/* 19: Gandalf FZA (rfc1993) */
971ae349f5Scvs2svn   "V42BIS",		/* 20: ARG->DATA.42bis compression */
981ae349f5Scvs2svn   "BSD",		/* 21: BSD LZW Compress */
991ae349f5Scvs2svn   "???",
1001ae349f5Scvs2svn   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1011ae349f5Scvs2svn   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1021342caedSBrian Somers 			/* 24: Deflate (according to pppd-2.3.*) */
1031ae349f5Scvs2svn   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1041ae349f5Scvs2svn   "DEFLATE",		/* 26: Deflate (rfc1979) */
1051ae349f5Scvs2svn };
1061ae349f5Scvs2svn 
1071ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1081ae349f5Scvs2svn 
1091ae349f5Scvs2svn static const char *
1101ae349f5Scvs2svn protoname(int proto)
1111ae349f5Scvs2svn {
1121ae349f5Scvs2svn   if (proto < 0 || proto > NCFTYPES)
1131ae349f5Scvs2svn     return "none";
1141ae349f5Scvs2svn   return cftypes[proto];
1151ae349f5Scvs2svn }
1161ae349f5Scvs2svn 
1171ae349f5Scvs2svn /* We support these algorithms, and Req them in the given order */
1181ae349f5Scvs2svn static const struct ccp_algorithm *algorithm[] = {
1191ae349f5Scvs2svn   &DeflateAlgorithm,
1201ae349f5Scvs2svn   &Pred1Algorithm,
1211ae349f5Scvs2svn   &PppdDeflateAlgorithm
1221ae349f5Scvs2svn };
1231ae349f5Scvs2svn 
1241ae349f5Scvs2svn #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1251ae349f5Scvs2svn 
1261ae349f5Scvs2svn int
127503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
1281ae349f5Scvs2svn {
129cd9647a1SBrian Somers   struct link *l = ChooseLink(arg);
130cd9647a1SBrian Somers   struct ccp *ccp = &l->ccp;
131503a7782SBrian Somers 
132b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
1331e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
134b6217683SBrian Somers   prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
135503a7782SBrian Somers                 protoname(ccp->my_proto), protoname(ccp->his_proto));
136b6217683SBrian Somers   prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
137503a7782SBrian Somers                 ccp->uncompout, ccp->compout,
138503a7782SBrian Somers                 ccp->compin, ccp->uncompin);
139cd9647a1SBrian Somers 
140b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n Defaults: ");
1411342caedSBrian Somers   prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry);
142b6217683SBrian Somers   prompt_Printf(arg->prompt, "           deflate windows: ");
143b6217683SBrian Somers   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
144b6217683SBrian Somers   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
1451342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
1461342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
1471342caedSBrian Somers   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
1481342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
1491342caedSBrian Somers   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
1501342caedSBrian Somers                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
1511ae349f5Scvs2svn   return 0;
1521ae349f5Scvs2svn }
1531ae349f5Scvs2svn 
1541ae349f5Scvs2svn void
1556d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1566d666775SBrian Somers          const struct fsm_parent *parent)
1571ae349f5Scvs2svn {
1587308ec68SBrian Somers   /* Initialise ourselves */
1593b0f8d2eSBrian Somers   static const char *timer_names[] =
1603b0f8d2eSBrian Somers     {"CCP restart", "CCP openmode", "CCP stopped"};
1613b0f8d2eSBrian Somers 
1623b0f8d2eSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
1633b0f8d2eSBrian Somers            bundle, l, parent, &ccp_Callbacks, timer_names);
164cd9647a1SBrian Somers 
16503036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
16603036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
167cd9647a1SBrian Somers   ccp->cfg.fsmretry = DEF_FSMRETRY;
1681342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
1691342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
1701342caedSBrian Somers   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
171cd9647a1SBrian Somers 
172503a7782SBrian Somers   ccp_Setup(ccp);
173503a7782SBrian Somers }
174503a7782SBrian Somers 
175503a7782SBrian Somers void
176503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
177503a7782SBrian Somers {
178503a7782SBrian Somers   /* Set ourselves up for a startup */
179503a7782SBrian Somers   ccp->fsm.open_mode = 0;
1805454ccd9SBrian Somers   ccp->fsm.maxconfig = 10;
181503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
182503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
18303036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
18403036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
18503036ec7SBrian Somers   ccp->in.opt.id = -1;
18603036ec7SBrian Somers   ccp->out.opt = NULL;
187503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
188503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
189503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
1901ae349f5Scvs2svn }
1911ae349f5Scvs2svn 
1921ae349f5Scvs2svn static void
1931ae349f5Scvs2svn CcpInitRestartCounter(struct fsm *fp)
1941ae349f5Scvs2svn {
1957308ec68SBrian Somers   /* Set fsm timer load */
196cd9647a1SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
197cd9647a1SBrian Somers 
198cd9647a1SBrian Somers   fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS;
1991ae349f5Scvs2svn   fp->restart = 5;
2001ae349f5Scvs2svn }
2011ae349f5Scvs2svn 
2021ae349f5Scvs2svn static void
2031ae349f5Scvs2svn CcpSendConfigReq(struct fsm *fp)
2041ae349f5Scvs2svn {
2057308ec68SBrian Somers   /* Send config REQ please */
206aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
20703036ec7SBrian Somers   struct ccp_opt **o;
20830c2f2ffSBrian Somers   u_char *cp, buff[100];
20903036ec7SBrian Somers   int f, alloc;
2101ae349f5Scvs2svn 
21130c2f2ffSBrian Somers   cp = buff;
21203036ec7SBrian Somers   o = &ccp->out.opt;
21303036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
21483d1af55SBrian Somers   ccp->my_proto = -1;
21503036ec7SBrian Somers   ccp->out.algorithm = -1;
2161ae349f5Scvs2svn   for (f = 0; f < NALGORITHMS; f++)
2171342caedSBrian Somers     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
2181342caedSBrian Somers         !REJECTED(ccp, algorithm[f]->id)) {
21903036ec7SBrian Somers       if (alloc) {
22003036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
22103036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
22203036ec7SBrian Somers         (*o)->val.len = 2;
22303036ec7SBrian Somers         (*o)->next = NULL;
22403036ec7SBrian Somers         (*o)->algorithm = f;
22503036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
22603036ec7SBrian Somers       } else {
22703036ec7SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
22803036ec7SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
22903036ec7SBrian Somers             break;
23003036ec7SBrian Somers         if (*o == NULL) {
23103036ec7SBrian Somers           LogPrintf(LogERROR, "CCP REQ buffer lost !\n");
23203036ec7SBrian Somers           break;
23303036ec7SBrian Somers         }
23403036ec7SBrian Somers       }
2351ae349f5Scvs2svn 
23603036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
23730c2f2ffSBrian Somers         LogPrintf(LogERROR, "CCP REQ buffer overrun !\n");
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 ! */
2901ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerStart.\n");
2911ae349f5Scvs2svn }
2921ae349f5Scvs2svn 
2931ae349f5Scvs2svn static void
2941ae349f5Scvs2svn CcpLayerFinish(struct fsm *fp)
2951ae349f5Scvs2svn {
2967308ec68SBrian Somers   /* We're now down */
297aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2981ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerFinish.\n");
29903036ec7SBrian Somers   if (ccp->in.state != NULL) {
30003036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
30103036ec7SBrian Somers     ccp->in.state = NULL;
3027308ec68SBrian Somers   }
30303036ec7SBrian Somers   if (ccp->out.state != NULL) {
30403036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
30503036ec7SBrian Somers     ccp->out.state = NULL;
3067308ec68SBrian Somers   }
3071ae349f5Scvs2svn }
3081ae349f5Scvs2svn 
3091ae349f5Scvs2svn static void
3101ae349f5Scvs2svn CcpLayerDown(struct fsm *fp)
3111ae349f5Scvs2svn {
3127308ec68SBrian Somers   /* About to come down */
3131ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerDown.\n");
3141ae349f5Scvs2svn }
3151ae349f5Scvs2svn 
3161ae349f5Scvs2svn /*
3171ae349f5Scvs2svn  *  Called when CCP has reached the OPEN state
3181ae349f5Scvs2svn  */
3191ae349f5Scvs2svn static void
3201ae349f5Scvs2svn CcpLayerUp(struct fsm *fp)
3211ae349f5Scvs2svn {
3227308ec68SBrian Somers   /* We're now up */
323aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
324455aabc3SBrian Somers   LogPrintf(LogCCP, "CcpLayerUp.\n");
32503036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
32603036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
32703036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
32803036ec7SBrian Somers     if (ccp->in.state == NULL) {
329247ab36dSBrian Somers       LogPrintf(LogERROR, "%s (in) initialisation failure\n",
33083d1af55SBrian Somers                 protoname(ccp->his_proto));
33183d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
332247ab36dSBrian Somers       FsmClose(fp);
333247ab36dSBrian Somers     }
33403036ec7SBrian Somers   }
33503036ec7SBrian Somers 
33603036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
33703036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
33803036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
33903036ec7SBrian Somers                        (&ccp->out.opt->val);
34003036ec7SBrian Somers     if (ccp->out.state == NULL) {
341247ab36dSBrian Somers       LogPrintf(LogERROR, "%s (out) initialisation failure\n",
34283d1af55SBrian Somers                 protoname(ccp->my_proto));
34383d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
344247ab36dSBrian Somers       FsmClose(fp);
345247ab36dSBrian Somers     }
34603036ec7SBrian Somers   }
34703036ec7SBrian Somers 
3481ae349f5Scvs2svn   LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n",
34983d1af55SBrian Somers             protoname(ccp->my_proto), ccp->my_proto,
35083d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
3511ae349f5Scvs2svn }
3521ae349f5Scvs2svn 
3531ae349f5Scvs2svn static void
35430c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
35530c2f2ffSBrian Somers                 struct fsm_decode *dec)
3561ae349f5Scvs2svn {
3577308ec68SBrian Somers   /* Deal with incoming data */
358aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3591ae349f5Scvs2svn   int type, length;
3601ae349f5Scvs2svn   int f;
36103036ec7SBrian Somers   const char *end;
3621ae349f5Scvs2svn 
3631ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
3641ae349f5Scvs2svn     type = *cp;
3651ae349f5Scvs2svn     length = cp[1];
36603036ec7SBrian Somers 
36703036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
36803036ec7SBrian Somers       length = sizeof(struct lcp_opt);
36903036ec7SBrian Somers       LogPrintf(LogCCP, "Warning: Truncating length to %d\n", length);
37003036ec7SBrian Somers     }
3711ae349f5Scvs2svn 
3721ae349f5Scvs2svn     for (f = NALGORITHMS-1; f > -1; f--)
3731ae349f5Scvs2svn       if (algorithm[f]->id == type)
3741ae349f5Scvs2svn         break;
3751ae349f5Scvs2svn 
37603036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
37703036ec7SBrian Somers     if (end == NULL)
37803036ec7SBrian Somers       end = "";
37903036ec7SBrian Somers 
38003036ec7SBrian Somers     if (type < NCFTYPES)
38103036ec7SBrian Somers       LogPrintf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
38203036ec7SBrian Somers     else
38303036ec7SBrian Somers       LogPrintf(LogCCP, " ???[%d] %s\n", length, end);
38403036ec7SBrian Somers 
3851ae349f5Scvs2svn     if (f == -1) {
3861ae349f5Scvs2svn       /* Don't understand that :-( */
3871ae349f5Scvs2svn       if (mode_type == MODE_REQ) {
38883d1af55SBrian Somers         ccp->my_reject |= (1 << type);
38930c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
39030c2f2ffSBrian Somers         dec->rejend += length;
3911ae349f5Scvs2svn       }
3921ae349f5Scvs2svn     } else {
39303036ec7SBrian Somers       struct ccp_opt *o;
3941ae349f5Scvs2svn 
3951ae349f5Scvs2svn       switch (mode_type) {
3961ae349f5Scvs2svn       case MODE_REQ:
3971342caedSBrian Somers 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
3981342caedSBrian Somers             ccp->in.algorithm == -1) {
39903036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
40003036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
4011ae349f5Scvs2svn           case MODE_REJ:
40203036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
40303036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
4041ae349f5Scvs2svn             break;
4051ae349f5Scvs2svn           case MODE_NAK:
40603036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
40703036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
4081ae349f5Scvs2svn             break;
4091ae349f5Scvs2svn           case MODE_ACK:
41030c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
41130c2f2ffSBrian Somers 	    dec->ackend += length;
41283d1af55SBrian Somers 	    ccp->his_proto = type;
41303036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4141ae349f5Scvs2svn             break;
4151ae349f5Scvs2svn           }
4161ae349f5Scvs2svn 	} else {
41730c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
41830c2f2ffSBrian Somers 	  dec->rejend += length;
4191ae349f5Scvs2svn 	}
4201ae349f5Scvs2svn 	break;
4211ae349f5Scvs2svn       case MODE_NAK:
42203036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
42303036ec7SBrian Somers           if (o->val.id == cp[0])
42403036ec7SBrian Somers             break;
42503036ec7SBrian Somers         if (o == NULL)
42603036ec7SBrian Somers           LogPrintf(LogCCP, "Warning: Ignoring peer NAK of unsent option\n");
42703036ec7SBrian Somers         else {
42803036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
42903036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
43083d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4311ae349f5Scvs2svn           else {
43283d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
43383d1af55SBrian Somers 	    ccp->my_proto = -1;
4341ae349f5Scvs2svn           }
43503036ec7SBrian Somers         }
4361ae349f5Scvs2svn         break;
4371ae349f5Scvs2svn       case MODE_REJ:
43883d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
43983d1af55SBrian Somers 	ccp->my_proto = -1;
4401ae349f5Scvs2svn 	break;
4411ae349f5Scvs2svn       }
4421ae349f5Scvs2svn     }
4431ae349f5Scvs2svn 
44403036ec7SBrian Somers     plen -= cp[1];
44503036ec7SBrian Somers     cp += cp[1];
4461ae349f5Scvs2svn   }
4471ae349f5Scvs2svn 
4481342caedSBrian Somers   if (mode_type != MODE_NOP)
4491342caedSBrian Somers     if (dec->rejend != dec->rej) {
45003036ec7SBrian Somers       /* rejects are preferred */
45103036ec7SBrian Somers       dec->ackend = dec->ack;
45203036ec7SBrian Somers       dec->nakend = dec->nak;
45303036ec7SBrian Somers       if (ccp->in.state == NULL) {
45483d1af55SBrian Somers         ccp->his_proto = -1;
45503036ec7SBrian Somers         ccp->in.algorithm = -1;
45603036ec7SBrian Somers       }
4571342caedSBrian Somers     } else if (dec->nakend != dec->nak) {
45803036ec7SBrian Somers       /* then NAKs */
45903036ec7SBrian Somers       dec->ackend = dec->ack;
46003036ec7SBrian Somers       if (ccp->in.state == NULL) {
46103036ec7SBrian Somers         ccp->his_proto = -1;
46203036ec7SBrian Somers         ccp->in.algorithm = -1;
463247ab36dSBrian Somers       }
4641ae349f5Scvs2svn     }
4651ae349f5Scvs2svn }
4661ae349f5Scvs2svn 
4671ae349f5Scvs2svn void
468f4768038SBrian Somers CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
4691ae349f5Scvs2svn {
4707308ec68SBrian Somers   /* Got PROTO_CCP from link */
471455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
472f4768038SBrian Somers     FsmInput(&ccp->fsm, bp);
473455aabc3SBrian Somers   else if (bundle_Phase(bundle) < PHASE_NETWORK) {
474455aabc3SBrian Somers     LogPrintf(LogCCP, "Error: Unexpected CCP in phase %s (ignored)\n",
475455aabc3SBrian Somers               bundle_PhaseName(bundle));
4761ae349f5Scvs2svn     pfree(bp);
4771ae349f5Scvs2svn   }
4781ae349f5Scvs2svn }
4791ae349f5Scvs2svn 
480503a7782SBrian Somers static void
481503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
4821ae349f5Scvs2svn {
4837308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
484f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
485f4768038SBrian Somers 
486f4768038SBrian Somers   if (ccp->reset_sent != -1) {
487f4768038SBrian Somers     if (id != ccp->reset_sent) {
4881ae349f5Scvs2svn       LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n",
489f4768038SBrian Somers                 id, ccp->reset_sent);
4901ae349f5Scvs2svn       return;
4911ae349f5Scvs2svn     }
4921ae349f5Scvs2svn     /* Whaddaya know - a correct reset ack */
493f4768038SBrian Somers   } else if (id == ccp->last_reset)
4941ae349f5Scvs2svn     LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n");
4951ae349f5Scvs2svn   else {
4961ae349f5Scvs2svn     LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id);
4971ae349f5Scvs2svn     return;
4981ae349f5Scvs2svn   }
4991ae349f5Scvs2svn 
500f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
501f4768038SBrian Somers   ccp->reset_sent = -1;
50203036ec7SBrian Somers   if (ccp->in.state != NULL)
50303036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
5041ae349f5Scvs2svn }
5051ae349f5Scvs2svn 
5061ae349f5Scvs2svn int
5073b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
508503a7782SBrian Somers              struct mbuf *m)
5091ae349f5Scvs2svn {
510503a7782SBrian Somers   /* Compress outgoing Network Layer data */
51103036ec7SBrian Somers   if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED &&
51203036ec7SBrian Somers       ccp->out.state != NULL)
51303036ec7SBrian Somers     return (*algorithm[ccp->out.algorithm]->o.Write)
51403036ec7SBrian Somers              (ccp->out.state, ccp, l, pri, proto, m);
5151ae349f5Scvs2svn   return 0;
5161ae349f5Scvs2svn }
5171ae349f5Scvs2svn 
5181ae349f5Scvs2svn struct mbuf *
519503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
5201ae349f5Scvs2svn {
521ee6c193fSBrian Somers   /*
522ee6c193fSBrian Somers    * If proto isn't PROTO_COMPD, we still want to pass it to the
523ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
524ee6c193fSBrian Somers    */
525503a7782SBrian Somers   if (ccp->fsm.state == ST_OPENED)
526ee6c193fSBrian Somers     if (*proto == PROTO_COMPD) {
5277308ec68SBrian Somers       /* Decompress incoming data */
5282267893fSBrian Somers       if (ccp->reset_sent != -1)
5291ae349f5Scvs2svn         /* Send another REQ and put the packet in the bit bucket */
530503a7782SBrian Somers         FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
5312267893fSBrian Somers       else if (ccp->in.state != NULL)
53203036ec7SBrian Somers         return (*algorithm[ccp->in.algorithm]->i.Read)
53303036ec7SBrian Somers                  (ccp->in.state, ccp, proto, bp);
534ee6c193fSBrian Somers       pfree(bp);
535ee6c193fSBrian Somers       bp = NULL;
53603036ec7SBrian Somers     } else if ((*proto & 0xfff1) == 0x21 && ccp->in.state != NULL)
537ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
53803036ec7SBrian Somers       (*algorithm[ccp->in.algorithm]->i.DictSetup)
53903036ec7SBrian Somers         (ccp->in.state, ccp, *proto, bp);
5401ae349f5Scvs2svn 
541ee6c193fSBrian Somers   return bp;
5421ae349f5Scvs2svn }
543