xref: /freebsd/usr.sbin/ppp/ccp.c (revision 3b0f8d2ed641ceeded11c0d3f253b0cacbf00880)
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  *
203b0f8d2eSBrian Somers  * $Id: ccp.c,v 1.30.2.28 1998/03/24 18:46:37 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o Support other compression protocols
241ae349f5Scvs2svn  */
251ae349f5Scvs2svn #include <sys/param.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>
321ae349f5Scvs2svn #include <string.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 "loadalias.h"
451ae349f5Scvs2svn #include "vars.h"
461ae349f5Scvs2svn #include "pred.h"
471ae349f5Scvs2svn #include "deflate.h"
485828db6dSBrian Somers #include "throughput.h"
495828db6dSBrian Somers #include "iplist.h"
50eaa4df37SBrian Somers #include "slcompress.h"
515828db6dSBrian Somers #include "ipcp.h"
525ca5389aSBrian Somers #include "filter.h"
5385b542cfSBrian Somers #include "descriptor.h"
5485b542cfSBrian Somers #include "prompt.h"
55879ed6faSBrian Somers #include "lqr.h"
56503a7782SBrian Somers #include "hdlc.h"
57503a7782SBrian Somers #include "link.h"
583b0f8d2eSBrian Somers #include "mp.h"
593b0f8d2eSBrian Somers #include "bundle.h"
60503a7782SBrian Somers #include "chat.h"
61e2ebb036SBrian Somers #include "auth.h"
62e2ebb036SBrian Somers #include "chap.h"
633b0f8d2eSBrian Somers #include "async.h"
643b0f8d2eSBrian Somers #include "physical.h"
65503a7782SBrian Somers #include "datalink.h"
661ae349f5Scvs2svn 
671ae349f5Scvs2svn static void CcpSendConfigReq(struct fsm *);
682267893fSBrian Somers static void CcpSentTerminateReq(struct fsm *);
692267893fSBrian Somers static void CcpSendTerminateAck(struct fsm *, u_char);
7030c2f2ffSBrian Somers static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
7130c2f2ffSBrian Somers                             struct fsm_decode *);
721ae349f5Scvs2svn static void CcpLayerStart(struct fsm *);
731ae349f5Scvs2svn static void CcpLayerFinish(struct fsm *);
741ae349f5Scvs2svn static void CcpLayerUp(struct fsm *);
751ae349f5Scvs2svn static void CcpLayerDown(struct fsm *);
761ae349f5Scvs2svn static void CcpInitRestartCounter(struct fsm *);
77503a7782SBrian Somers static void CcpRecvResetReq(struct fsm *);
78503a7782SBrian Somers static void CcpRecvResetAck(struct fsm *, u_char);
791ae349f5Scvs2svn 
8083d1af55SBrian Somers static struct fsm_callbacks ccp_Callbacks = {
8183d1af55SBrian Somers   CcpLayerUp,
8283d1af55SBrian Somers   CcpLayerDown,
8383d1af55SBrian Somers   CcpLayerStart,
846d666775SBrian Somers   CcpLayerFinish,
8583d1af55SBrian Somers   CcpInitRestartCounter,
8683d1af55SBrian Somers   CcpSendConfigReq,
872267893fSBrian Somers   CcpSentTerminateReq,
8883d1af55SBrian Somers   CcpSendTerminateAck,
89503a7782SBrian Somers   CcpDecodeConfig,
90503a7782SBrian Somers   CcpRecvResetReq,
91503a7782SBrian Somers   CcpRecvResetAck
9283d1af55SBrian Somers };
9383d1af55SBrian Somers 
941ae349f5Scvs2svn static char const *cftypes[] = {
951ae349f5Scvs2svn   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
961ae349f5Scvs2svn   "OUI",		/* 0: OUI */
971ae349f5Scvs2svn   "PRED1",		/* 1: Predictor type 1 */
981ae349f5Scvs2svn   "PRED2",		/* 2: Predictor type 2 */
991ae349f5Scvs2svn   "PUDDLE",		/* 3: Puddle Jumber */
1001ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
1011ae349f5Scvs2svn   "???", "???", "???", "???", "???", "???",
1021ae349f5Scvs2svn   "HWPPC",		/* 16: Hewlett-Packard PPC */
1031ae349f5Scvs2svn   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
1048f2e5827SBrian Somers   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
1051ae349f5Scvs2svn   "GAND",		/* 19: Gandalf FZA (rfc1993) */
1061ae349f5Scvs2svn   "V42BIS",		/* 20: ARG->DATA.42bis compression */
1071ae349f5Scvs2svn   "BSD",		/* 21: BSD LZW Compress */
1081ae349f5Scvs2svn   "???",
1091ae349f5Scvs2svn   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
1101ae349f5Scvs2svn   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
1111ae349f5Scvs2svn 			/* 24: Deflate (according to pppd-2.3.1) */
1121ae349f5Scvs2svn   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
1131ae349f5Scvs2svn   "DEFLATE",		/* 26: Deflate (rfc1979) */
1141ae349f5Scvs2svn };
1151ae349f5Scvs2svn 
1161ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1171ae349f5Scvs2svn 
1181ae349f5Scvs2svn static const char *
1191ae349f5Scvs2svn protoname(int proto)
1201ae349f5Scvs2svn {
1211ae349f5Scvs2svn   if (proto < 0 || proto > NCFTYPES)
1221ae349f5Scvs2svn     return "none";
1231ae349f5Scvs2svn   return cftypes[proto];
1241ae349f5Scvs2svn }
1251ae349f5Scvs2svn 
1261ae349f5Scvs2svn /* We support these algorithms, and Req them in the given order */
1271ae349f5Scvs2svn static const struct ccp_algorithm *algorithm[] = {
1281ae349f5Scvs2svn   &DeflateAlgorithm,
1291ae349f5Scvs2svn   &Pred1Algorithm,
1301ae349f5Scvs2svn   &PppdDeflateAlgorithm
1311ae349f5Scvs2svn };
1321ae349f5Scvs2svn 
1331ae349f5Scvs2svn #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
1341ae349f5Scvs2svn 
1351ae349f5Scvs2svn int
136503a7782SBrian Somers ccp_ReportStatus(struct cmdargs const *arg)
1371ae349f5Scvs2svn {
1383b0f8d2eSBrian Somers   struct ccp *ccp = &ChooseLink(arg)->ccp;
139503a7782SBrian Somers 
140503a7782SBrian Somers   prompt_Printf(&prompt, "%s [%s]\n", ccp->fsm.name,
1411e991daaSBrian Somers                 State2Nam(ccp->fsm.state));
14285b542cfSBrian Somers   prompt_Printf(&prompt, "My protocol = %s, His protocol = %s\n",
143503a7782SBrian Somers                 protoname(ccp->my_proto), protoname(ccp->his_proto));
14485b542cfSBrian Somers   prompt_Printf(&prompt, "Output: %ld --> %ld,  Input: %ld --> %ld\n",
145503a7782SBrian Somers                 ccp->uncompout, ccp->compout,
146503a7782SBrian Somers                 ccp->compin, ccp->uncompin);
1471ae349f5Scvs2svn   return 0;
1481ae349f5Scvs2svn }
1491ae349f5Scvs2svn 
1501ae349f5Scvs2svn void
1516d666775SBrian Somers ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
1526d666775SBrian Somers          const struct fsm_parent *parent)
1531ae349f5Scvs2svn {
1547308ec68SBrian Somers   /* Initialise ourselves */
1553b0f8d2eSBrian Somers   static const char *timer_names[] =
1563b0f8d2eSBrian Somers     {"CCP restart", "CCP openmode", "CCP stopped"};
1573b0f8d2eSBrian Somers 
1583b0f8d2eSBrian Somers   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
1593b0f8d2eSBrian Somers            bundle, l, parent, &ccp_Callbacks, timer_names);
16003036ec7SBrian Somers   ccp->cfg.deflate.in.winsize = 0;
16103036ec7SBrian Somers   ccp->cfg.deflate.out.winsize = 15;
162503a7782SBrian Somers   ccp_Setup(ccp);
163503a7782SBrian Somers }
164503a7782SBrian Somers 
165503a7782SBrian Somers void
166503a7782SBrian Somers ccp_Setup(struct ccp *ccp)
167503a7782SBrian Somers {
168503a7782SBrian Somers   /* Set ourselves up for a startup */
169503a7782SBrian Somers   ccp->fsm.open_mode = 0;
1705454ccd9SBrian Somers   ccp->fsm.maxconfig = 10;
171503a7782SBrian Somers   ccp->his_proto = ccp->my_proto = -1;
172503a7782SBrian Somers   ccp->reset_sent = ccp->last_reset = -1;
17303036ec7SBrian Somers   ccp->in.algorithm = ccp->out.algorithm = -1;
17403036ec7SBrian Somers   ccp->in.state = ccp->out.state = NULL;
17503036ec7SBrian Somers   ccp->in.opt.id = -1;
17603036ec7SBrian Somers   ccp->out.opt = NULL;
177503a7782SBrian Somers   ccp->his_reject = ccp->my_reject = 0;
178503a7782SBrian Somers   ccp->uncompout = ccp->compout = 0;
179503a7782SBrian Somers   ccp->uncompin = ccp->compin = 0;
1801ae349f5Scvs2svn }
1811ae349f5Scvs2svn 
1821ae349f5Scvs2svn static void
1831ae349f5Scvs2svn CcpInitRestartCounter(struct fsm *fp)
1841ae349f5Scvs2svn {
1857308ec68SBrian Somers   /* Set fsm timer load */
1861ae349f5Scvs2svn   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
1871ae349f5Scvs2svn   fp->restart = 5;
1881ae349f5Scvs2svn }
1891ae349f5Scvs2svn 
1901ae349f5Scvs2svn static void
1911ae349f5Scvs2svn CcpSendConfigReq(struct fsm *fp)
1921ae349f5Scvs2svn {
1937308ec68SBrian Somers   /* Send config REQ please */
194aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
19503036ec7SBrian Somers   struct ccp_opt **o;
19630c2f2ffSBrian Somers   u_char *cp, buff[100];
19703036ec7SBrian Somers   int f, alloc;
1981ae349f5Scvs2svn 
19930c2f2ffSBrian Somers   cp = buff;
20003036ec7SBrian Somers   o = &ccp->out.opt;
20103036ec7SBrian Somers   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
20283d1af55SBrian Somers   ccp->my_proto = -1;
20303036ec7SBrian Somers   ccp->out.algorithm = -1;
2041ae349f5Scvs2svn   for (f = 0; f < NALGORITHMS; f++)
20583d1af55SBrian Somers     if (Enabled(algorithm[f]->Conf) && !REJECTED(ccp, algorithm[f]->id)) {
20603036ec7SBrian Somers       if (alloc) {
20703036ec7SBrian Somers         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
20803036ec7SBrian Somers         (*o)->val.id = algorithm[f]->id;
20903036ec7SBrian Somers         (*o)->val.len = 2;
21003036ec7SBrian Somers         (*o)->next = NULL;
21103036ec7SBrian Somers         (*o)->algorithm = f;
21203036ec7SBrian Somers         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
21303036ec7SBrian Somers       } else {
21403036ec7SBrian Somers         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
21503036ec7SBrian Somers           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
21603036ec7SBrian Somers             break;
21703036ec7SBrian Somers         if (*o == NULL) {
21803036ec7SBrian Somers           LogPrintf(LogERROR, "CCP REQ buffer lost !\n");
21903036ec7SBrian Somers           break;
22003036ec7SBrian Somers         }
22103036ec7SBrian Somers       }
2221ae349f5Scvs2svn 
22303036ec7SBrian Somers       if (cp + (*o)->val.len > buff + sizeof buff) {
22430c2f2ffSBrian Somers         LogPrintf(LogERROR, "CCP REQ buffer overrun !\n");
22530c2f2ffSBrian Somers         break;
22630c2f2ffSBrian Somers       }
2272267893fSBrian Somers       memcpy(cp, &(*o)->val, (*o)->val.len);
2282267893fSBrian Somers       cp += (*o)->val.len;
22903036ec7SBrian Somers 
23003036ec7SBrian Somers       ccp->my_proto = (*o)->val.id;
23103036ec7SBrian Somers       ccp->out.algorithm = f;
23203036ec7SBrian Somers 
23303036ec7SBrian Somers       if (alloc)
23403036ec7SBrian Somers         o = &(*o)->next;
2351ae349f5Scvs2svn     }
2362267893fSBrian Somers 
2372267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff);
2381ae349f5Scvs2svn }
2391ae349f5Scvs2svn 
2401ae349f5Scvs2svn void
2411ae349f5Scvs2svn CcpSendResetReq(struct fsm *fp)
2421ae349f5Scvs2svn {
2437308ec68SBrian Somers   /* We can't read our input - ask peer to reset */
244aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2452267893fSBrian Somers 
24683d1af55SBrian Somers   ccp->reset_sent = fp->reqid;
24783d1af55SBrian Somers   ccp->last_reset = -1;
2481ae349f5Scvs2svn   FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
2491ae349f5Scvs2svn }
2501ae349f5Scvs2svn 
2511ae349f5Scvs2svn static void
2522267893fSBrian Somers CcpSentTerminateReq(struct fsm *fp)
2531ae349f5Scvs2svn {
2547308ec68SBrian Somers   /* Term REQ just sent by FSM */
2551ae349f5Scvs2svn }
2561ae349f5Scvs2svn 
2571ae349f5Scvs2svn static void
2582267893fSBrian Somers CcpSendTerminateAck(struct fsm *fp, u_char id)
2591ae349f5Scvs2svn {
2607308ec68SBrian Somers   /* Send Term ACK please */
2612267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
2621ae349f5Scvs2svn }
2631ae349f5Scvs2svn 
264503a7782SBrian Somers static void
2651ae349f5Scvs2svn CcpRecvResetReq(struct fsm *fp)
2661ae349f5Scvs2svn {
2677308ec68SBrian Somers   /* Got a reset REQ, reset outgoing dictionary */
268aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
26903036ec7SBrian Somers   if (ccp->out.state != NULL)
27003036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
2711ae349f5Scvs2svn }
2721ae349f5Scvs2svn 
2731ae349f5Scvs2svn static void
2741ae349f5Scvs2svn CcpLayerStart(struct fsm *fp)
2751ae349f5Scvs2svn {
2767308ec68SBrian Somers   /* We're about to start up ! */
2771ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerStart.\n");
2781ae349f5Scvs2svn }
2791ae349f5Scvs2svn 
2801ae349f5Scvs2svn static void
2811ae349f5Scvs2svn CcpLayerFinish(struct fsm *fp)
2821ae349f5Scvs2svn {
2837308ec68SBrian Somers   /* We're now down */
284aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
2851ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerFinish.\n");
28603036ec7SBrian Somers   if (ccp->in.state != NULL) {
28703036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
28803036ec7SBrian Somers     ccp->in.state = NULL;
2897308ec68SBrian Somers   }
29003036ec7SBrian Somers   if (ccp->out.state != NULL) {
29103036ec7SBrian Somers     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
29203036ec7SBrian Somers     ccp->out.state = NULL;
2937308ec68SBrian Somers   }
2941ae349f5Scvs2svn }
2951ae349f5Scvs2svn 
2961ae349f5Scvs2svn static void
2971ae349f5Scvs2svn CcpLayerDown(struct fsm *fp)
2981ae349f5Scvs2svn {
2997308ec68SBrian Somers   /* About to come down */
3001ae349f5Scvs2svn   LogPrintf(LogCCP, "CcpLayerDown.\n");
3011ae349f5Scvs2svn }
3021ae349f5Scvs2svn 
3031ae349f5Scvs2svn /*
3041ae349f5Scvs2svn  *  Called when CCP has reached the OPEN state
3051ae349f5Scvs2svn  */
3061ae349f5Scvs2svn static void
3071ae349f5Scvs2svn CcpLayerUp(struct fsm *fp)
3081ae349f5Scvs2svn {
3097308ec68SBrian Somers   /* We're now up */
310aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
311455aabc3SBrian Somers   LogPrintf(LogCCP, "CcpLayerUp.\n");
31203036ec7SBrian Somers   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
31303036ec7SBrian Somers       ccp->in.algorithm < NALGORITHMS) {
31403036ec7SBrian Somers     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
31503036ec7SBrian Somers     if (ccp->in.state == NULL) {
316247ab36dSBrian Somers       LogPrintf(LogERROR, "%s (in) initialisation failure\n",
31783d1af55SBrian Somers                 protoname(ccp->his_proto));
31883d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
319247ab36dSBrian Somers       FsmClose(fp);
320247ab36dSBrian Somers     }
32103036ec7SBrian Somers   }
32203036ec7SBrian Somers 
32303036ec7SBrian Somers   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
32403036ec7SBrian Somers       ccp->out.algorithm < NALGORITHMS) {
32503036ec7SBrian Somers     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
32603036ec7SBrian Somers                        (&ccp->out.opt->val);
32703036ec7SBrian Somers     if (ccp->out.state == NULL) {
328247ab36dSBrian Somers       LogPrintf(LogERROR, "%s (out) initialisation failure\n",
32983d1af55SBrian Somers                 protoname(ccp->my_proto));
33083d1af55SBrian Somers       ccp->his_proto = ccp->my_proto = -1;
331247ab36dSBrian Somers       FsmClose(fp);
332247ab36dSBrian Somers     }
33303036ec7SBrian Somers   }
33403036ec7SBrian Somers 
3351ae349f5Scvs2svn   LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n",
33683d1af55SBrian Somers             protoname(ccp->my_proto), ccp->my_proto,
33783d1af55SBrian Somers             protoname(ccp->his_proto), ccp->his_proto);
3381ae349f5Scvs2svn }
3391ae349f5Scvs2svn 
3401ae349f5Scvs2svn static void
34130c2f2ffSBrian Somers CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
34230c2f2ffSBrian Somers                 struct fsm_decode *dec)
3431ae349f5Scvs2svn {
3447308ec68SBrian Somers   /* Deal with incoming data */
345aad81d1eSBrian Somers   struct ccp *ccp = fsm2ccp(fp);
3461ae349f5Scvs2svn   int type, length;
3471ae349f5Scvs2svn   int f;
34803036ec7SBrian Somers   const char *end;
3491ae349f5Scvs2svn 
3501ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
3511ae349f5Scvs2svn     type = *cp;
3521ae349f5Scvs2svn     length = cp[1];
35303036ec7SBrian Somers 
35403036ec7SBrian Somers     if (length > sizeof(struct lcp_opt)) {
35503036ec7SBrian Somers       length = sizeof(struct lcp_opt);
35603036ec7SBrian Somers       LogPrintf(LogCCP, "Warning: Truncating length to %d\n", length);
35703036ec7SBrian Somers     }
3581ae349f5Scvs2svn 
3591ae349f5Scvs2svn     for (f = NALGORITHMS-1; f > -1; f--)
3601ae349f5Scvs2svn       if (algorithm[f]->id == type)
3611ae349f5Scvs2svn         break;
3621ae349f5Scvs2svn 
36303036ec7SBrian Somers     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
36403036ec7SBrian Somers     if (end == NULL)
36503036ec7SBrian Somers       end = "";
36603036ec7SBrian Somers 
36703036ec7SBrian Somers     if (type < NCFTYPES)
36803036ec7SBrian Somers       LogPrintf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
36903036ec7SBrian Somers     else
37003036ec7SBrian Somers       LogPrintf(LogCCP, " ???[%d] %s\n", length, end);
37103036ec7SBrian Somers 
3721ae349f5Scvs2svn     if (f == -1) {
3731ae349f5Scvs2svn       /* Don't understand that :-( */
3741ae349f5Scvs2svn       if (mode_type == MODE_REQ) {
37583d1af55SBrian Somers         ccp->my_reject |= (1 << type);
37630c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
37730c2f2ffSBrian Somers         dec->rejend += length;
3781ae349f5Scvs2svn       }
3791ae349f5Scvs2svn     } else {
38003036ec7SBrian Somers       struct ccp_opt *o;
3811ae349f5Scvs2svn 
3821ae349f5Scvs2svn       switch (mode_type) {
3831ae349f5Scvs2svn       case MODE_REQ:
38403036ec7SBrian Somers 	if (Acceptable(algorithm[f]->Conf) && ccp->in.algorithm == -1) {
38503036ec7SBrian Somers 	  memcpy(&ccp->in.opt, cp, length);
38603036ec7SBrian Somers           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
3871ae349f5Scvs2svn           case MODE_REJ:
38803036ec7SBrian Somers 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
38903036ec7SBrian Somers 	    dec->rejend += ccp->in.opt.len;
3901ae349f5Scvs2svn             break;
3911ae349f5Scvs2svn           case MODE_NAK:
39203036ec7SBrian Somers 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
39303036ec7SBrian Somers 	    dec->nakend += ccp->in.opt.len;
3941ae349f5Scvs2svn             break;
3951ae349f5Scvs2svn           case MODE_ACK:
39630c2f2ffSBrian Somers 	    memcpy(dec->ackend, cp, length);
39730c2f2ffSBrian Somers 	    dec->ackend += length;
39883d1af55SBrian Somers 	    ccp->his_proto = type;
39903036ec7SBrian Somers             ccp->in.algorithm = f;		/* This one'll do :-) */
4001ae349f5Scvs2svn             break;
4011ae349f5Scvs2svn           }
4021ae349f5Scvs2svn 	} else {
40330c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
40430c2f2ffSBrian Somers 	  dec->rejend += length;
4051ae349f5Scvs2svn 	}
4061ae349f5Scvs2svn 	break;
4071ae349f5Scvs2svn       case MODE_NAK:
40803036ec7SBrian Somers         for (o = ccp->out.opt; o != NULL; o = o->next)
40903036ec7SBrian Somers           if (o->val.id == cp[0])
41003036ec7SBrian Somers             break;
41103036ec7SBrian Somers         if (o == NULL)
41203036ec7SBrian Somers           LogPrintf(LogCCP, "Warning: Ignoring peer NAK of unsent option\n");
41303036ec7SBrian Somers         else {
41403036ec7SBrian Somers 	  memcpy(&o->val, cp, length);
41503036ec7SBrian Somers           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
41683d1af55SBrian Somers             ccp->my_proto = algorithm[f]->id;
4171ae349f5Scvs2svn           else {
41883d1af55SBrian Somers 	    ccp->his_reject |= (1 << type);
41983d1af55SBrian Somers 	    ccp->my_proto = -1;
4201ae349f5Scvs2svn           }
42103036ec7SBrian Somers         }
4221ae349f5Scvs2svn         break;
4231ae349f5Scvs2svn       case MODE_REJ:
42483d1af55SBrian Somers 	ccp->his_reject |= (1 << type);
42583d1af55SBrian Somers 	ccp->my_proto = -1;
4261ae349f5Scvs2svn 	break;
4271ae349f5Scvs2svn       }
4281ae349f5Scvs2svn     }
4291ae349f5Scvs2svn 
43003036ec7SBrian Somers     plen -= cp[1];
43103036ec7SBrian Somers     cp += cp[1];
4321ae349f5Scvs2svn   }
4331ae349f5Scvs2svn 
43430c2f2ffSBrian Somers   if (mode_type != MODE_NOP && dec->rejend != dec->rej) {
43503036ec7SBrian Somers     /* rejects are preferred */
43603036ec7SBrian Somers     dec->ackend = dec->ack;
43703036ec7SBrian Somers     dec->nakend = dec->nak;
43803036ec7SBrian Somers     if (ccp->in.state == NULL) {
43983d1af55SBrian Somers       ccp->his_proto = -1;
44003036ec7SBrian Somers       ccp->in.algorithm = -1;
44103036ec7SBrian Somers     }
44203036ec7SBrian Somers   } else if (mode_type != MODE_NOP && dec->nakend != dec->nak) {
44303036ec7SBrian Somers     /* then NAKs */
44403036ec7SBrian Somers     dec->ackend = dec->ack;
44503036ec7SBrian Somers     if (ccp->in.state == NULL) {
44603036ec7SBrian Somers       ccp->his_proto = -1;
44703036ec7SBrian Somers       ccp->in.algorithm = -1;
448247ab36dSBrian Somers     }
4491ae349f5Scvs2svn   }
4501ae349f5Scvs2svn }
4511ae349f5Scvs2svn 
4521ae349f5Scvs2svn void
453f4768038SBrian Somers CcpInput(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
4541ae349f5Scvs2svn {
4557308ec68SBrian Somers   /* Got PROTO_CCP from link */
456455aabc3SBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
457f4768038SBrian Somers     FsmInput(&ccp->fsm, bp);
458455aabc3SBrian Somers   else if (bundle_Phase(bundle) < PHASE_NETWORK) {
459455aabc3SBrian Somers     LogPrintf(LogCCP, "Error: Unexpected CCP in phase %s (ignored)\n",
460455aabc3SBrian Somers               bundle_PhaseName(bundle));
4611ae349f5Scvs2svn     pfree(bp);
4621ae349f5Scvs2svn   }
4631ae349f5Scvs2svn }
4641ae349f5Scvs2svn 
465503a7782SBrian Somers static void
466503a7782SBrian Somers CcpRecvResetAck(struct fsm *fp, u_char id)
4671ae349f5Scvs2svn {
4687308ec68SBrian Somers   /* Got a reset ACK, reset incoming dictionary */
469f4768038SBrian Somers   struct ccp *ccp = fsm2ccp(fp);
470f4768038SBrian Somers 
471f4768038SBrian Somers   if (ccp->reset_sent != -1) {
472f4768038SBrian Somers     if (id != ccp->reset_sent) {
4731ae349f5Scvs2svn       LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n",
474f4768038SBrian Somers                 id, ccp->reset_sent);
4751ae349f5Scvs2svn       return;
4761ae349f5Scvs2svn     }
4771ae349f5Scvs2svn     /* Whaddaya know - a correct reset ack */
478f4768038SBrian Somers   } else if (id == ccp->last_reset)
4791ae349f5Scvs2svn     LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n");
4801ae349f5Scvs2svn   else {
4811ae349f5Scvs2svn     LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id);
4821ae349f5Scvs2svn     return;
4831ae349f5Scvs2svn   }
4841ae349f5Scvs2svn 
485f4768038SBrian Somers   ccp->last_reset = ccp->reset_sent;
486f4768038SBrian Somers   ccp->reset_sent = -1;
48703036ec7SBrian Somers   if (ccp->in.state != NULL)
48803036ec7SBrian Somers     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
4891ae349f5Scvs2svn }
4901ae349f5Scvs2svn 
4911ae349f5Scvs2svn int
4923b0f8d2eSBrian Somers ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
493503a7782SBrian Somers              struct mbuf *m)
4941ae349f5Scvs2svn {
495503a7782SBrian Somers   /* Compress outgoing Network Layer data */
49603036ec7SBrian Somers   if ((proto & 0xfff1) == 0x21 && ccp->fsm.state == ST_OPENED &&
49703036ec7SBrian Somers       ccp->out.state != NULL)
49803036ec7SBrian Somers     return (*algorithm[ccp->out.algorithm]->o.Write)
49903036ec7SBrian Somers              (ccp->out.state, ccp, l, pri, proto, m);
5001ae349f5Scvs2svn   return 0;
5011ae349f5Scvs2svn }
5021ae349f5Scvs2svn 
5031ae349f5Scvs2svn struct mbuf *
504503a7782SBrian Somers ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
5051ae349f5Scvs2svn {
506ee6c193fSBrian Somers   /*
507ee6c193fSBrian Somers    * If proto isn't PROTO_COMPD, we still want to pass it to the
508ee6c193fSBrian Somers    * decompression routines so that the dictionary's updated
509ee6c193fSBrian Somers    */
510503a7782SBrian Somers   if (ccp->fsm.state == ST_OPENED)
511ee6c193fSBrian Somers     if (*proto == PROTO_COMPD) {
5127308ec68SBrian Somers       /* Decompress incoming data */
5132267893fSBrian Somers       if (ccp->reset_sent != -1)
5141ae349f5Scvs2svn         /* Send another REQ and put the packet in the bit bucket */
515503a7782SBrian Somers         FsmOutput(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
5162267893fSBrian Somers       else if (ccp->in.state != NULL)
51703036ec7SBrian Somers         return (*algorithm[ccp->in.algorithm]->i.Read)
51803036ec7SBrian Somers                  (ccp->in.state, ccp, proto, bp);
519ee6c193fSBrian Somers       pfree(bp);
520ee6c193fSBrian Somers       bp = NULL;
52103036ec7SBrian Somers     } else if ((*proto & 0xfff1) == 0x21 && ccp->in.state != NULL)
522ee6c193fSBrian Somers       /* Add incoming Network Layer traffic to our dictionary */
52303036ec7SBrian Somers       (*algorithm[ccp->in.algorithm]->i.DictSetup)
52403036ec7SBrian Somers         (ccp->in.state, ccp, *proto, bp);
5251ae349f5Scvs2svn 
526ee6c193fSBrian Somers   return bp;
5271ae349f5Scvs2svn }
528