178189Sbrian/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
478189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
578189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
678189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
778189Sbrian * All rights reserved.
86059Samurai *
978189Sbrian * Redistribution and use in source and binary forms, with or without
1078189Sbrian * modification, are permitted provided that the following conditions
1178189Sbrian * are met:
1278189Sbrian * 1. Redistributions of source code must retain the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer.
1478189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1578189Sbrian *    notice, this list of conditions and the following disclaimer in the
1678189Sbrian *    documentation and/or other materials provided with the distribution.
176059Samurai *
1878189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1978189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2078189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2178189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2278189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2378189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2478189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2578189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2678189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2778189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2878189Sbrian * SUCH DAMAGE.
296059Samurai *
3050479Speter * $FreeBSD: stable/11/usr.sbin/ppp/ccp.c 330449 2018-03-05 07:26:05Z eadler $
316059Samurai */
3278189Sbrian
3343313Sbrian#include <sys/param.h>
3430715Sbrian#include <netinet/in.h>
3536285Sbrian#include <netinet/in_systm.h>
3636285Sbrian#include <netinet/ip.h>
3781634Sbrian#include <sys/socket.h>
3836285Sbrian#include <sys/un.h>
3930715Sbrian
40102500Sbrian#include <stdarg.h>
4130715Sbrian#include <stdio.h>
4236285Sbrian#include <stdlib.h>
4349472Sbrian#include <string.h>	/* memcpy() on some archs */
4436285Sbrian#include <termios.h>
4530715Sbrian
4646686Sbrian#include "layer.h"
4737009Sbrian#include "defs.h"
4831343Sbrian#include "command.h"
4930715Sbrian#include "mbuf.h"
5030715Sbrian#include "log.h"
5130715Sbrian#include "timer.h"
526059Samurai#include "fsm.h"
5346686Sbrian#include "proto.h"
5413389Sphk#include "pred.h"
5531514Sbrian#include "deflate.h"
5636285Sbrian#include "throughput.h"
5736285Sbrian#include "iplist.h"
5836285Sbrian#include "slcompress.h"
5938557Sbrian#include "lqr.h"
6038557Sbrian#include "hdlc.h"
6163484Sbrian#include "lcp.h"
6263484Sbrian#include "ccp.h"
6381634Sbrian#include "ncpaddr.h"
6436285Sbrian#include "ipcp.h"
6536285Sbrian#include "filter.h"
6636285Sbrian#include "descriptor.h"
6736285Sbrian#include "prompt.h"
6836285Sbrian#include "link.h"
6936285Sbrian#include "mp.h"
7036285Sbrian#include "async.h"
7136285Sbrian#include "physical.h"
7243313Sbrian#ifndef NORADIUS
7343313Sbrian#include "radius.h"
7443313Sbrian#endif
7593418Sbrian#ifndef NODES
7667910Sbrian#include "mppe.h"
7767910Sbrian#endif
7881634Sbrian#include "ipv6cp.h"
7981634Sbrian#include "ncp.h"
8036285Sbrian#include "bundle.h"
818857Srgrimes
8226516Sbrianstatic void CcpSendConfigReq(struct fsm *);
8336285Sbrianstatic void CcpSentTerminateReq(struct fsm *);
8436285Sbrianstatic void CcpSendTerminateAck(struct fsm *, u_char);
8594894Sbrianstatic void CcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
8636285Sbrian                            struct fsm_decode *);
8726516Sbrianstatic void CcpLayerStart(struct fsm *);
8826516Sbrianstatic void CcpLayerFinish(struct fsm *);
8936285Sbrianstatic int CcpLayerUp(struct fsm *);
9026516Sbrianstatic void CcpLayerDown(struct fsm *);
9144305Sbrianstatic void CcpInitRestartCounter(struct fsm *, int);
9278411Sbrianstatic int CcpRecvResetReq(struct fsm *);
9336285Sbrianstatic void CcpRecvResetAck(struct fsm *, u_char);
946059Samurai
9536285Sbrianstatic struct fsm_callbacks ccp_Callbacks = {
966059Samurai  CcpLayerUp,
976059Samurai  CcpLayerDown,
986059Samurai  CcpLayerStart,
996059Samurai  CcpLayerFinish,
1006059Samurai  CcpInitRestartCounter,
1016059Samurai  CcpSendConfigReq,
10236285Sbrian  CcpSentTerminateReq,
1036059Samurai  CcpSendTerminateAck,
1046059Samurai  CcpDecodeConfig,
10536285Sbrian  CcpRecvResetReq,
10636285Sbrian  CcpRecvResetAck
1076059Samurai};
1086059Samurai
10955146Sbrianstatic const char * const ccp_TimerNames[] =
11036285Sbrian  {"CCP restart", "CCP openmode", "CCP stopped"};
11136285Sbrian
11258034Sbrianstatic const char *
11358034Sbrianprotoname(int proto)
11458034Sbrian{
11558034Sbrian  static char const * const cftypes[] = {
11658034Sbrian    /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
11758034Sbrian    "OUI",		/* 0: OUI */
11858034Sbrian    "PRED1",		/* 1: Predictor type 1 */
11958034Sbrian    "PRED2",		/* 2: Predictor type 2 */
12058034Sbrian    "PUDDLE",		/* 3: Puddle Jumber */
12158034Sbrian    NULL, NULL, NULL, NULL, NULL, NULL,
12258034Sbrian    NULL, NULL, NULL, NULL, NULL, NULL,
12358034Sbrian    "HWPPC",		/* 16: Hewlett-Packard PPC */
12458034Sbrian    "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
12567910Sbrian    "MPPE",		/* 18: Microsoft PPC (rfc2118) and */
12667910Sbrian			/*     Microsoft PPE (draft-ietf-pppext-mppe) */
12758034Sbrian    "GAND",		/* 19: Gandalf FZA (rfc1993) */
12858034Sbrian    "V42BIS",		/* 20: ARG->DATA.42bis compression */
12958034Sbrian    "BSD",		/* 21: BSD LZW Compress */
13058034Sbrian    NULL,
13158034Sbrian    "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
13258034Sbrian    "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
13336285Sbrian			/* 24: Deflate (according to pppd-2.3.*) */
13458034Sbrian    "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
13558034Sbrian    "DEFLATE",		/* 26: Deflate (rfc1979) */
13658034Sbrian  };
1376059Samurai
138134789Sbrian  if (proto < 0 || (unsigned)proto > sizeof cftypes / sizeof *cftypes ||
13985985Sbrian      cftypes[proto] == NULL) {
14085985Sbrian    if (proto == -1)
14185985Sbrian      return "none";
14258034Sbrian    return HexStr(proto, NULL, 0);
14385985Sbrian  }
14431171Sbrian
14531514Sbrian  return cftypes[proto];
14631514Sbrian}
14731514Sbrian
14831518Sbrian/* We support these algorithms, and Req them in the given order */
14955146Sbrianstatic const struct ccp_algorithm * const algorithm[] = {
15031518Sbrian  &DeflateAlgorithm,
15131514Sbrian  &Pred1Algorithm,
15231518Sbrian  &PppdDeflateAlgorithm
15393418Sbrian#ifndef NODES
15467910Sbrian  , &MPPEAlgorithm
15567910Sbrian#endif
15631514Sbrian};
15731514Sbrian
15831962Sbrian#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
15931514Sbrian
16025630Sbrianint
16136285Sbrianccp_ReportStatus(struct cmdargs const *arg)
1626059Samurai{
16378411Sbrian  struct ccp_opt **o;
16436285Sbrian  struct link *l;
16536285Sbrian  struct ccp *ccp;
16678411Sbrian  int f;
16736285Sbrian
16837210Sbrian  l = command_ChooseLink(arg);
16936285Sbrian  ccp = &l->ccp;
17036285Sbrian
17136285Sbrian  prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
17236285Sbrian                State2Nam(ccp->fsm.state));
17346686Sbrian  if (ccp->fsm.state == ST_OPENED) {
17446686Sbrian    prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
17546686Sbrian                  protoname(ccp->my_proto), protoname(ccp->his_proto));
17646686Sbrian    prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
17746686Sbrian                  ccp->uncompout, ccp->compout,
17846686Sbrian                  ccp->compin, ccp->uncompin);
17946686Sbrian  }
18036285Sbrian
18178411Sbrian  if (ccp->in.algorithm != -1)
18278411Sbrian    prompt_Printf(arg->prompt, "\n Input Options:  %s\n",
18378411Sbrian                  (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt));
18478411Sbrian
18578411Sbrian  if (ccp->out.algorithm != -1) {
18678411Sbrian    o = &ccp->out.opt;
18778411Sbrian    for (f = 0; f < ccp->out.algorithm; f++)
18878411Sbrian      if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
18978411Sbrian        o = &(*o)->next;
19078411Sbrian    prompt_Printf(arg->prompt, " Output Options: %s\n",
19178411Sbrian                  (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val));
19278411Sbrian  }
19378411Sbrian
19436285Sbrian  prompt_Printf(arg->prompt, "\n Defaults: ");
19544305Sbrian  prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
19644305Sbrian                " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
19744305Sbrian                ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
19844305Sbrian                ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
19936285Sbrian  prompt_Printf(arg->prompt, "           deflate windows: ");
20036285Sbrian  prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
20136285Sbrian  prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
20293418Sbrian#ifndef NODES
20378411Sbrian  prompt_Printf(arg->prompt, "           MPPE: ");
20478411Sbrian  if (ccp->cfg.mppe.keybits)
20578411Sbrian    prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits);
20678411Sbrian  else
20778411Sbrian    prompt_Printf(arg->prompt, "any bits, ");
20878411Sbrian  switch (ccp->cfg.mppe.state) {
20978411Sbrian  case MPPE_STATEFUL:
21079370Sbrian    prompt_Printf(arg->prompt, "stateful");
21178411Sbrian    break;
21278411Sbrian  case MPPE_STATELESS:
21378411Sbrian    prompt_Printf(arg->prompt, "stateless");
21478411Sbrian    break;
21578411Sbrian  case MPPE_ANYSTATE:
21678411Sbrian    prompt_Printf(arg->prompt, "any state");
21778411Sbrian    break;
21878411Sbrian  }
21978411Sbrian  prompt_Printf(arg->prompt, "%s\n",
22078411Sbrian                ccp->cfg.mppe.required ? ", required" : "");
22178411Sbrian#endif
22278411Sbrian
22378411Sbrian  prompt_Printf(arg->prompt, "\n           DEFLATE:    %s\n",
22436285Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
22536285Sbrian  prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
22636285Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
22736285Sbrian  prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
22836285Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
22993418Sbrian#ifndef NODES
23078411Sbrian  prompt_Printf(arg->prompt, "           MPPE:       %s\n",
23167910Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
23267910Sbrian#endif
23325630Sbrian  return 0;
2346059Samurai}
2356059Samurai
23636285Sbrianvoid
23736285Sbrianccp_SetupCallbacks(struct ccp *ccp)
2386059Samurai{
23936285Sbrian  ccp->fsm.fn = &ccp_Callbacks;
24036285Sbrian  ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
24136285Sbrian  ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
24236285Sbrian  ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
24331539Sbrian}
24431539Sbrian
24531539Sbrianvoid
24636285Sbrianccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
24736285Sbrian         const struct fsm_parent *parent)
24831539Sbrian{
24936285Sbrian  /* Initialise ourselves */
25036285Sbrian
25144305Sbrian  fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
25236285Sbrian           bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
25336285Sbrian
25436285Sbrian  ccp->cfg.deflate.in.winsize = 0;
25536285Sbrian  ccp->cfg.deflate.out.winsize = 15;
25644305Sbrian  ccp->cfg.fsm.timeout = DEF_FSMRETRY;
25744305Sbrian  ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
25844305Sbrian  ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
25936285Sbrian  ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
26036285Sbrian  ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
26136285Sbrian  ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
26293418Sbrian#ifndef NODES
26378411Sbrian  ccp->cfg.mppe.keybits = 0;
26478411Sbrian  ccp->cfg.mppe.state = MPPE_ANYSTATE;
26578411Sbrian  ccp->cfg.mppe.required = 0;
26668906Sbrian  ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
26767910Sbrian#endif
26836285Sbrian
26936285Sbrian  ccp_Setup(ccp);
2706059Samurai}
2716059Samurai
27236285Sbrianvoid
27336285Sbrianccp_Setup(struct ccp *ccp)
27436285Sbrian{
27536285Sbrian  /* Set ourselves up for a startup */
27636285Sbrian  ccp->fsm.open_mode = 0;
27736285Sbrian  ccp->his_proto = ccp->my_proto = -1;
27836285Sbrian  ccp->reset_sent = ccp->last_reset = -1;
27936285Sbrian  ccp->in.algorithm = ccp->out.algorithm = -1;
28036285Sbrian  ccp->in.state = ccp->out.state = NULL;
28194894Sbrian  ccp->in.opt.hdr.id = -1;
28236285Sbrian  ccp->out.opt = NULL;
28336285Sbrian  ccp->his_reject = ccp->my_reject = 0;
28436285Sbrian  ccp->uncompout = ccp->compout = 0;
28536285Sbrian  ccp->uncompin = ccp->compin = 0;
28636285Sbrian}
28736285Sbrian
28878411Sbrian/*
28978411Sbrian * Is ccp *REQUIRED* ?
29078411Sbrian * We ask each of the configured ccp protocols if they're required and
29178411Sbrian * return TRUE if they are.
29278411Sbrian *
29378411Sbrian * It's not possible for the peer to reject a required ccp protocol
29478411Sbrian * without our state machine bringing the supporting lcp layer down.
29578411Sbrian *
29678411Sbrian * If ccp is required but not open, the NCP layer should not push
29778411Sbrian * any data into the link.
29878411Sbrian */
29978411Sbrianint
30078411Sbrianccp_Required(struct ccp *ccp)
30178411Sbrian{
302134789Sbrian  unsigned f;
30378411Sbrian
30478411Sbrian  for (f = 0; f < NALGORITHMS; f++)
30578411Sbrian    if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
30678411Sbrian        (*algorithm[f]->Required)(&ccp->fsm))
30778411Sbrian      return 1;
30878411Sbrian
30978411Sbrian  return 0;
31078411Sbrian}
31178411Sbrian
31279165Sbrian/*
31379165Sbrian * Report whether it's possible to increase a packet's size after
31479165Sbrian * compression (and by how much).
31579165Sbrian */
31679165Sbrianint
31779165Sbrianccp_MTUOverhead(struct ccp *ccp)
31879165Sbrian{
31979396Sbrian  if (ccp->fsm.state == ST_OPENED && ccp->out.algorithm >= 0)
32079165Sbrian    return algorithm[ccp->out.algorithm]->o.MTUOverhead;
32179165Sbrian
32279165Sbrian  return 0;
32379165Sbrian}
32479165Sbrian
3256059Samuraistatic void
32644305SbrianCcpInitRestartCounter(struct fsm *fp, int what)
3276059Samurai{
32836285Sbrian  /* Set fsm timer load */
32936285Sbrian  struct ccp *ccp = fsm2ccp(fp);
33036285Sbrian
33144305Sbrian  fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
33244305Sbrian  switch (what) {
33344305Sbrian    case FSM_REQ_TIMER:
33444305Sbrian      fp->restart = ccp->cfg.fsm.maxreq;
33544305Sbrian      break;
33644305Sbrian    case FSM_TRM_TIMER:
33744305Sbrian      fp->restart = ccp->cfg.fsm.maxtrm;
33844305Sbrian      break;
33944305Sbrian    default:
34044305Sbrian      fp->restart = 1;
34144305Sbrian      break;
34244305Sbrian  }
3436059Samurai}
3446059Samurai
3456059Samuraistatic void
34630715SbrianCcpSendConfigReq(struct fsm *fp)
3476059Samurai{
34836285Sbrian  /* Send config REQ please */
34936285Sbrian  struct ccp *ccp = fsm2ccp(fp);
35036285Sbrian  struct ccp_opt **o;
35136285Sbrian  u_char *cp, buff[100];
352134789Sbrian  unsigned f;
353134789Sbrian  int alloc;
3546059Samurai
35536285Sbrian  cp = buff;
35636285Sbrian  o = &ccp->out.opt;
35736285Sbrian  alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
35836285Sbrian  ccp->my_proto = -1;
35936285Sbrian  ccp->out.algorithm = -1;
36031514Sbrian  for (f = 0; f < NALGORITHMS; f++)
36136285Sbrian    if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
36272025Sbrian        !REJECTED(ccp, algorithm[f]->id) &&
36372025Sbrian        (*algorithm[f]->Usable)(fp)) {
36431514Sbrian
36536285Sbrian      if (!alloc)
36636285Sbrian        for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
367134789Sbrian          if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == (int)f)
36836285Sbrian            break;
36936285Sbrian
37036285Sbrian      if (alloc || *o == NULL) {
371136375Sbrian        if ((*o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt))) == NULL) {
372136375Sbrian	  log_Printf(LogERROR, "%s: Not enough memory for CCP REQ !\n",
373136375Sbrian		     fp->link->name);
374136375Sbrian	  break;
375136375Sbrian	}
37694894Sbrian        (*o)->val.hdr.id = algorithm[f]->id;
37794894Sbrian        (*o)->val.hdr.len = 2;
37836285Sbrian        (*o)->next = NULL;
37936285Sbrian        (*o)->algorithm = f;
38098132Sbrian        (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
38136285Sbrian      }
38236285Sbrian
38394894Sbrian      if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
38436285Sbrian        log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
38536285Sbrian        break;
38636285Sbrian      }
38794894Sbrian      memcpy(cp, &(*o)->val, (*o)->val.hdr.len);
38894894Sbrian      cp += (*o)->val.hdr.len;
38936285Sbrian
39094894Sbrian      ccp->my_proto = (*o)->val.hdr.id;
39136285Sbrian      ccp->out.algorithm = f;
39236285Sbrian
39336285Sbrian      if (alloc)
39436285Sbrian        o = &(*o)->next;
39531514Sbrian    }
39636285Sbrian
39747695Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
3986059Samurai}
3996059Samurai
4006059Samuraivoid
40136285Sbrianccp_SendResetReq(struct fsm *fp)
4026059Samurai{
40336285Sbrian  /* We can't read our input - ask peer to reset */
40436285Sbrian  struct ccp *ccp = fsm2ccp(fp);
40536285Sbrian
40636285Sbrian  ccp->reset_sent = fp->reqid;
40736285Sbrian  ccp->last_reset = -1;
40847695Sbrian  fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
4096059Samurai}
4106059Samurai
4116059Samuraistatic void
412134789SbrianCcpSentTerminateReq(struct fsm *fp __unused)
4136059Samurai{
41436285Sbrian  /* Term REQ just sent by FSM */
4156059Samurai}
4166059Samurai
4176059Samuraistatic void
41836285SbrianCcpSendTerminateAck(struct fsm *fp, u_char id)
4196059Samurai{
42036285Sbrian  /* Send Term ACK please */
42147695Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
4226059Samurai}
4236059Samurai
42478411Sbrianstatic int
42530715SbrianCcpRecvResetReq(struct fsm *fp)
4266059Samurai{
42736285Sbrian  /* Got a reset REQ, reset outgoing dictionary */
42836285Sbrian  struct ccp *ccp = fsm2ccp(fp);
42978411Sbrian  if (ccp->out.state == NULL)
43078411Sbrian    return 1;
43178411Sbrian  return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
4326059Samurai}
4336059Samurai
4346059Samuraistatic void
43530715SbrianCcpLayerStart(struct fsm *fp)
4366059Samurai{
43736285Sbrian  /* We're about to start up ! */
43844305Sbrian  struct ccp *ccp = fsm2ccp(fp);
43944305Sbrian
44037210Sbrian  log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
44144305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
4426059Samurai}
4436059Samurai
4446059Samuraistatic void
44537160SbrianCcpLayerDown(struct fsm *fp)
4466059Samurai{
44737160Sbrian  /* About to come down */
44836285Sbrian  struct ccp *ccp = fsm2ccp(fp);
44936285Sbrian  struct ccp_opt *next;
45036285Sbrian
45137210Sbrian  log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
45236285Sbrian  if (ccp->in.state != NULL) {
45336285Sbrian    (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
45436285Sbrian    ccp->in.state = NULL;
45536285Sbrian    ccp->in.algorithm = -1;
45636285Sbrian  }
45736285Sbrian  if (ccp->out.state != NULL) {
45836285Sbrian    (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
45936285Sbrian    ccp->out.state = NULL;
46036285Sbrian    ccp->out.algorithm = -1;
46136285Sbrian  }
46236285Sbrian  ccp->his_reject = ccp->my_reject = 0;
46398243Sbrian
46436285Sbrian  while (ccp->out.opt) {
46536285Sbrian    next = ccp->out.opt->next;
46636285Sbrian    free(ccp->out.opt);
46736285Sbrian    ccp->out.opt = next;
46836285Sbrian  }
46937160Sbrian  ccp_Setup(ccp);
4706059Samurai}
4716059Samurai
4726059Samuraistatic void
47337160SbrianCcpLayerFinish(struct fsm *fp)
4746059Samurai{
47537160Sbrian  /* We're now down */
47668423Sbrian  struct ccp *ccp = fsm2ccp(fp);
47768423Sbrian  struct ccp_opt *next;
47868423Sbrian
47937210Sbrian  log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
48068423Sbrian
48168423Sbrian  /*
48268423Sbrian   * Nuke options that may be left over from sending a REQ but never
48368423Sbrian   * coming up.
48468423Sbrian   */
48568423Sbrian  while (ccp->out.opt) {
48668423Sbrian    next = ccp->out.opt->next;
48768423Sbrian    free(ccp->out.opt);
48868423Sbrian    ccp->out.opt = next;
48968423Sbrian  }
49078411Sbrian
49178411Sbrian  if (ccp_Required(ccp)) {
49278411Sbrian    if (fp->link->lcp.fsm.state == ST_OPENED)
49378411Sbrian      log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
49478411Sbrian    fsm_Close(&fp->link->lcp.fsm);
49578411Sbrian  }
4966059Samurai}
4976059Samurai
49846828Sbrian/*  Called when CCP has reached the OPEN state */
49936285Sbrianstatic int
50030715SbrianCcpLayerUp(struct fsm *fp)
5016059Samurai{
50236285Sbrian  /* We're now up */
50336285Sbrian  struct ccp *ccp = fsm2ccp(fp);
50468423Sbrian  struct ccp_opt **o;
505134789Sbrian  unsigned f, fail;
50644305Sbrian
50779165Sbrian  for (f = fail = 0; f < NALGORITHMS; f++)
50879165Sbrian    if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
50979165Sbrian        (*algorithm[f]->Required)(&ccp->fsm) &&
510134789Sbrian        (ccp->in.algorithm != (int)f || ccp->out.algorithm != (int)f)) {
51179165Sbrian      /* Blow it all away - we haven't negotiated a required algorithm */
51279165Sbrian      log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
51379165Sbrian                 fp->link->name, protoname(algorithm[f]->id));
51479165Sbrian      fail = 1;
51579165Sbrian    }
51679165Sbrian
51779165Sbrian  if (fail) {
51879165Sbrian    ccp->his_proto = ccp->my_proto = -1;
51979165Sbrian    fsm_Close(fp);
52079165Sbrian    fsm_Close(&fp->link->lcp.fsm);
52179165Sbrian    return 0;
52279165Sbrian  }
52379165Sbrian
52437210Sbrian  log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
52544305Sbrian
52636285Sbrian  if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
527134789Sbrian      ccp->in.algorithm < (int)NALGORITHMS) {
52898132Sbrian    ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
52998132Sbrian      (fp->bundle, &ccp->in.opt);
53036285Sbrian    if (ccp->in.state == NULL) {
53136285Sbrian      log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
53236285Sbrian                fp->link->name, protoname(ccp->his_proto));
53336285Sbrian      ccp->his_proto = ccp->my_proto = -1;
53436285Sbrian      fsm_Close(fp);
53544305Sbrian      return 0;
53636285Sbrian    }
53732246Sbrian  }
5386059Samurai
53968423Sbrian  o = &ccp->out.opt;
540134789Sbrian  if (ccp->out.algorithm > 0)
541134789Sbrian    for (f = 0; f < (unsigned)ccp->out.algorithm; f++)
542134789Sbrian      if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
543134789Sbrian	o = &(*o)->next;
54468423Sbrian
54536285Sbrian  if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
546134789Sbrian      ccp->out.algorithm < (int)NALGORITHMS) {
54798132Sbrian    ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
54898132Sbrian      (fp->bundle, &(*o)->val);
54936285Sbrian    if (ccp->out.state == NULL) {
55036285Sbrian      log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
55136285Sbrian                fp->link->name, protoname(ccp->my_proto));
55236285Sbrian      ccp->his_proto = ccp->my_proto = -1;
55336285Sbrian      fsm_Close(fp);
55444305Sbrian      return 0;
55531514Sbrian    }
55636285Sbrian  }
55731514Sbrian
55844305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
55944305Sbrian
56036285Sbrian  log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
56136285Sbrian            fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
56236285Sbrian            protoname(ccp->his_proto), ccp->his_proto);
56344305Sbrian
56436285Sbrian  return 1;
5656059Samurai}
5666059Samurai
5676059Samuraistatic void
56894894SbrianCcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
56936285Sbrian                struct fsm_decode *dec)
5706059Samurai{
57136285Sbrian  /* Deal with incoming data */
57236285Sbrian  struct ccp *ccp = fsm2ccp(fp);
57394894Sbrian  int f;
57494894Sbrian  const char *disp;
57594894Sbrian  struct fsm_opt *opt;
5766059Samurai
57746310Sbrian  if (mode_type == MODE_REQ)
57846310Sbrian    ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
57946310Sbrian
580134789Sbrian  while (end >= cp + sizeof(opt->hdr)) {
58194894Sbrian    if ((opt = fsm_readopt(&cp)) == NULL)
58236285Sbrian      break;
58336285Sbrian
58431514Sbrian    for (f = NALGORITHMS-1; f > -1; f--)
58594894Sbrian      if (algorithm[f]->id == opt->hdr.id)
58631514Sbrian        break;
5876059Samurai
58894894Sbrian    disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
58994894Sbrian    if (disp == NULL)
59094894Sbrian      disp = "";
59136285Sbrian
59294894Sbrian    log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
59394894Sbrian               opt->hdr.len, disp);
59436285Sbrian
59531514Sbrian    if (f == -1) {
59631514Sbrian      /* Don't understand that :-( */
59731514Sbrian      if (mode_type == MODE_REQ) {
59894894Sbrian        ccp->my_reject |= (1 << opt->hdr.id);
59994894Sbrian        fsm_rej(dec, opt);
60031514Sbrian      }
60131514Sbrian    } else {
60236285Sbrian      struct ccp_opt *o;
60331514Sbrian
60431034Sbrian      switch (mode_type) {
6056059Samurai      case MODE_REQ:
60694894Sbrian        if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
60772025Sbrian            (*algorithm[f]->Usable)(fp) &&
60836285Sbrian            ccp->in.algorithm == -1) {
60994894Sbrian          memcpy(&ccp->in.opt, opt, opt->hdr.len);
61098132Sbrian          switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
61131514Sbrian          case MODE_REJ:
61294894Sbrian            fsm_rej(dec, &ccp->in.opt);
61331514Sbrian            break;
61431514Sbrian          case MODE_NAK:
61594894Sbrian            fsm_nak(dec, &ccp->in.opt);
61631514Sbrian            break;
61731514Sbrian          case MODE_ACK:
61894894Sbrian            fsm_ack(dec, &ccp->in.opt);
61994894Sbrian            ccp->his_proto = opt->hdr.id;
620134789Sbrian            ccp->in.algorithm = (int)f;		/* This one'll do :-) */
62131514Sbrian            break;
62231514Sbrian          }
62394894Sbrian        } else {
62494894Sbrian          fsm_rej(dec, opt);
62594894Sbrian        }
62694894Sbrian        break;
6276059Samurai      case MODE_NAK:
62836285Sbrian        for (o = ccp->out.opt; o != NULL; o = o->next)
62994894Sbrian          if (o->val.hdr.id == opt->hdr.id)
63036285Sbrian            break;
63136285Sbrian        if (o == NULL)
63267912Sbrian          log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
63367912Sbrian                     " option\n", fp->link->name);
63431514Sbrian        else {
63594894Sbrian          memcpy(&o->val, opt, opt->hdr.len);
63698132Sbrian          if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
63798132Sbrian              MODE_ACK)
63836285Sbrian            ccp->my_proto = algorithm[f]->id;
63936285Sbrian          else {
64094894Sbrian            ccp->his_reject |= (1 << opt->hdr.id);
64194894Sbrian            ccp->my_proto = -1;
64278411Sbrian            if (algorithm[f]->Required(fp)) {
64378411Sbrian              log_Printf(LogWARN, "%s: Cannot understand peers (required)"
64478411Sbrian                         " %s negotiation\n", fp->link->name,
64578411Sbrian                         protoname(algorithm[f]->id));
64678411Sbrian              fsm_Close(&fp->link->lcp.fsm);
64778411Sbrian            }
64836285Sbrian          }
64931514Sbrian        }
65031514Sbrian        break;
6516059Samurai      case MODE_REJ:
65294894Sbrian        ccp->his_reject |= (1 << opt->hdr.id);
65394894Sbrian        ccp->my_proto = -1;
65478411Sbrian        if (algorithm[f]->Required(fp)) {
65578411Sbrian          log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
65678411Sbrian                     fp->link->name, protoname(algorithm[f]->id));
65778411Sbrian          fsm_Close(&fp->link->lcp.fsm);
65878411Sbrian        }
65994894Sbrian        break;
6606059Samurai      }
6616059Samurai    }
6626059Samurai  }
66331514Sbrian
66436285Sbrian  if (mode_type != MODE_NOP) {
66594894Sbrian    fsm_opt_normalise(dec);
66694894Sbrian    if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
66736285Sbrian      if (ccp->in.state == NULL) {
66836285Sbrian        ccp->his_proto = -1;
66936285Sbrian        ccp->in.algorithm = -1;
67036285Sbrian      }
67136285Sbrian    }
67231514Sbrian  }
6736059Samurai}
6746059Samurai
67546686Sbrianextern struct mbuf *
67646686Sbrianccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
6776059Samurai{
67836285Sbrian  /* Got PROTO_CCP from link */
67954912Sbrian  m_settype(bp, MB_CCPIN);
68036285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
68146686Sbrian    fsm_Input(&l->ccp.fsm, bp);
6826059Samurai  else {
68336285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
68436285Sbrian      log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
68546686Sbrian                 l->ccp.fsm.link->name, bundle_PhaseName(bundle));
68654912Sbrian    m_freem(bp);
6876059Samurai  }
68846686Sbrian  return NULL;
6896059Samurai}
69031514Sbrian
69136285Sbrianstatic void
69236285SbrianCcpRecvResetAck(struct fsm *fp, u_char id)
69331514Sbrian{
69436285Sbrian  /* Got a reset ACK, reset incoming dictionary */
69536285Sbrian  struct ccp *ccp = fsm2ccp(fp);
69636285Sbrian
69736285Sbrian  if (ccp->reset_sent != -1) {
69836285Sbrian    if (id != ccp->reset_sent) {
69944650Sbrian      log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
70036285Sbrian                " ignored\n", fp->link->name, id, ccp->reset_sent);
70132381Sbrian      return;
70232381Sbrian    }
70332381Sbrian    /* Whaddaya know - a correct reset ack */
70436285Sbrian  } else if (id == ccp->last_reset)
70536285Sbrian    log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
70644650Sbrian               fp->link->name);
70732381Sbrian  else {
70844650Sbrian    log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
70944650Sbrian               fp->link->name, id);
71032381Sbrian    return;
71132381Sbrian  }
71232381Sbrian
71336285Sbrian  ccp->last_reset = ccp->reset_sent;
71436285Sbrian  ccp->reset_sent = -1;
71536285Sbrian  if (ccp->in.state != NULL)
71636285Sbrian    (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
71731514Sbrian}
71831514Sbrian
71946686Sbrianstatic struct mbuf *
720134789Sbrianccp_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp,
72146686Sbrian              int pri, u_short *proto)
72231514Sbrian{
72378411Sbrian  if (PROTO_COMPRESSIBLE(*proto)) {
72478411Sbrian    if (l->ccp.fsm.state != ST_OPENED) {
72578411Sbrian      if (ccp_Required(&l->ccp)) {
72678411Sbrian        /* The NCP layer shouldn't have let this happen ! */
72778411Sbrian        log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
72878411Sbrian                   " required CCP layer\n", l->name);
72978411Sbrian        m_freem(bp);
73078411Sbrian        bp = NULL;
73178411Sbrian      }
73278411Sbrian    } else if (l->ccp.out.state != NULL) {
73378411Sbrian      bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
73478411Sbrian             (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
73578411Sbrian      switch (*proto) {
73678411Sbrian        case PROTO_ICOMPD:
73778411Sbrian          m_settype(bp, MB_ICOMPDOUT);
73878411Sbrian          break;
73978411Sbrian        case PROTO_COMPD:
74078411Sbrian          m_settype(bp, MB_COMPDOUT);
74178411Sbrian          break;
74278411Sbrian      }
74347695Sbrian    }
74447695Sbrian  }
74546686Sbrian
74646686Sbrian  return bp;
74731514Sbrian}
74831514Sbrian
74946686Sbrianstatic struct mbuf *
750134789Sbrianccp_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp,
751134789Sbrian	      u_short *proto)
75231514Sbrian{
75336285Sbrian  /*
75436285Sbrian   * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
75536285Sbrian   * decompression routines so that the dictionary's updated
75636285Sbrian   */
75746686Sbrian  if (l->ccp.fsm.state == ST_OPENED) {
75836285Sbrian    if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
75936285Sbrian      /* Decompress incoming data */
76046686Sbrian      if (l->ccp.reset_sent != -1)
76136285Sbrian        /* Send another REQ and put the packet in the bit bucket */
76247695Sbrian        fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
76347695Sbrian                   MB_CCPOUT);
76447695Sbrian      else if (l->ccp.in.state != NULL) {
76547695Sbrian        bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
76647695Sbrian               (l->ccp.in.state, &l->ccp, proto, bp);
76747695Sbrian        switch (*proto) {
76847695Sbrian          case PROTO_ICOMPD:
76954912Sbrian            m_settype(bp, MB_ICOMPDIN);
77047695Sbrian            break;
77147695Sbrian          case PROTO_COMPD:
77254912Sbrian            m_settype(bp, MB_COMPDIN);
77347695Sbrian            break;
77447695Sbrian        }
77547695Sbrian        return bp;
77647695Sbrian      }
77754912Sbrian      m_freem(bp);
77836285Sbrian      bp = NULL;
77947061Sbrian    } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
78036285Sbrian      /* Add incoming Network Layer traffic to our dictionary */
78146686Sbrian      (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
78246686Sbrian        (l->ccp.in.state, &l->ccp, *proto, bp);
78399234Sbrian    }
78436285Sbrian  }
78536285Sbrian
78636285Sbrian  return bp;
78731514Sbrian}
78831514Sbrian
78936285Sbrianu_short
79036285Sbrianccp_Proto(struct ccp *ccp)
79131514Sbrian{
79236285Sbrian  return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
79336285Sbrian         PROTO_COMPD : PROTO_ICOMPD;
79431514Sbrian}
79536310Sbrian
79637320Sbrianint
79736310Sbrianccp_SetOpenMode(struct ccp *ccp)
79836310Sbrian{
79936310Sbrian  int f;
80036310Sbrian
80136310Sbrian  for (f = 0; f < CCP_NEG_TOTAL; f++)
80237320Sbrian    if (IsEnabled(ccp->cfg.neg[f])) {
80336310Sbrian      ccp->fsm.open_mode = 0;
80437320Sbrian      return 1;
80537320Sbrian    }
80636310Sbrian
80737320Sbrian  ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
80837320Sbrian
80937320Sbrian  for (f = 0; f < CCP_NEG_TOTAL; f++)
81037320Sbrian    if (IsAccepted(ccp->cfg.neg[f]))
81137320Sbrian      return 1;
81237320Sbrian
81337320Sbrian  return 0;				/* No CCP at all */
81436310Sbrian}
81546686Sbrian
81672025Sbrianint
817134789Sbrianccp_DefaultUsable(struct fsm *fp __unused)
81872025Sbrian{
81972025Sbrian  return 1;
82072025Sbrian}
82172025Sbrian
82278411Sbrianint
823134789Sbrianccp_DefaultRequired(struct fsm *fp __unused)
82478411Sbrian{
82578411Sbrian  return 0;
82678411Sbrian}
82778411Sbrian
82846686Sbrianstruct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
829