178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD$
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in.h>
3336285Sbrian#include <netinet/in_systm.h>
3436285Sbrian#include <netinet/ip.h>
3581634Sbrian#include <sys/socket.h>
3636285Sbrian#include <sys/un.h>
3730715Sbrian
38102500Sbrian#include <stdarg.h>
3930715Sbrian#include <stdio.h>
4036285Sbrian#include <stdlib.h>
4149472Sbrian#include <string.h>	/* memcpy() on some archs */
4236285Sbrian#include <termios.h>
4330715Sbrian
4446686Sbrian#include "layer.h"
4537009Sbrian#include "defs.h"
4631343Sbrian#include "command.h"
4730715Sbrian#include "mbuf.h"
4830715Sbrian#include "log.h"
4930715Sbrian#include "timer.h"
506059Samurai#include "fsm.h"
5146686Sbrian#include "proto.h"
5213389Sphk#include "pred.h"
5331514Sbrian#include "deflate.h"
5436285Sbrian#include "throughput.h"
5536285Sbrian#include "iplist.h"
5636285Sbrian#include "slcompress.h"
5738557Sbrian#include "lqr.h"
5838557Sbrian#include "hdlc.h"
5963484Sbrian#include "lcp.h"
6063484Sbrian#include "ccp.h"
6181634Sbrian#include "ncpaddr.h"
6236285Sbrian#include "ipcp.h"
6336285Sbrian#include "filter.h"
6436285Sbrian#include "descriptor.h"
6536285Sbrian#include "prompt.h"
6636285Sbrian#include "link.h"
6736285Sbrian#include "mp.h"
6836285Sbrian#include "async.h"
6936285Sbrian#include "physical.h"
7043313Sbrian#ifndef NORADIUS
7143313Sbrian#include "radius.h"
7243313Sbrian#endif
7393418Sbrian#ifndef NODES
7467910Sbrian#include "mppe.h"
7567910Sbrian#endif
7681634Sbrian#include "ipv6cp.h"
7781634Sbrian#include "ncp.h"
7836285Sbrian#include "bundle.h"
798857Srgrimes
8026516Sbrianstatic void CcpSendConfigReq(struct fsm *);
8136285Sbrianstatic void CcpSentTerminateReq(struct fsm *);
8236285Sbrianstatic void CcpSendTerminateAck(struct fsm *, u_char);
8394894Sbrianstatic void CcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
8436285Sbrian                            struct fsm_decode *);
8526516Sbrianstatic void CcpLayerStart(struct fsm *);
8626516Sbrianstatic void CcpLayerFinish(struct fsm *);
8736285Sbrianstatic int CcpLayerUp(struct fsm *);
8826516Sbrianstatic void CcpLayerDown(struct fsm *);
8944305Sbrianstatic void CcpInitRestartCounter(struct fsm *, int);
9078411Sbrianstatic int CcpRecvResetReq(struct fsm *);
9136285Sbrianstatic void CcpRecvResetAck(struct fsm *, u_char);
926059Samurai
9336285Sbrianstatic struct fsm_callbacks ccp_Callbacks = {
946059Samurai  CcpLayerUp,
956059Samurai  CcpLayerDown,
966059Samurai  CcpLayerStart,
976059Samurai  CcpLayerFinish,
986059Samurai  CcpInitRestartCounter,
996059Samurai  CcpSendConfigReq,
10036285Sbrian  CcpSentTerminateReq,
1016059Samurai  CcpSendTerminateAck,
1026059Samurai  CcpDecodeConfig,
10336285Sbrian  CcpRecvResetReq,
10436285Sbrian  CcpRecvResetAck
1056059Samurai};
1066059Samurai
10755146Sbrianstatic const char * const ccp_TimerNames[] =
10836285Sbrian  {"CCP restart", "CCP openmode", "CCP stopped"};
10936285Sbrian
11058034Sbrianstatic const char *
11158034Sbrianprotoname(int proto)
11258034Sbrian{
11358034Sbrian  static char const * const cftypes[] = {
11458034Sbrian    /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
11558034Sbrian    "OUI",		/* 0: OUI */
11658034Sbrian    "PRED1",		/* 1: Predictor type 1 */
11758034Sbrian    "PRED2",		/* 2: Predictor type 2 */
11858034Sbrian    "PUDDLE",		/* 3: Puddle Jumber */
11958034Sbrian    NULL, NULL, NULL, NULL, NULL, NULL,
12058034Sbrian    NULL, NULL, NULL, NULL, NULL, NULL,
12158034Sbrian    "HWPPC",		/* 16: Hewlett-Packard PPC */
12258034Sbrian    "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
12367910Sbrian    "MPPE",		/* 18: Microsoft PPC (rfc2118) and */
12467910Sbrian			/*     Microsoft PPE (draft-ietf-pppext-mppe) */
12558034Sbrian    "GAND",		/* 19: Gandalf FZA (rfc1993) */
12658034Sbrian    "V42BIS",		/* 20: ARG->DATA.42bis compression */
12758034Sbrian    "BSD",		/* 21: BSD LZW Compress */
12858034Sbrian    NULL,
12958034Sbrian    "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
13058034Sbrian    "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
13136285Sbrian			/* 24: Deflate (according to pppd-2.3.*) */
13258034Sbrian    "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
13358034Sbrian    "DEFLATE",		/* 26: Deflate (rfc1979) */
13458034Sbrian  };
1356059Samurai
136134789Sbrian  if (proto < 0 || (unsigned)proto > sizeof cftypes / sizeof *cftypes ||
13785985Sbrian      cftypes[proto] == NULL) {
13885985Sbrian    if (proto == -1)
13985985Sbrian      return "none";
14058034Sbrian    return HexStr(proto, NULL, 0);
14185985Sbrian  }
14231171Sbrian
14331514Sbrian  return cftypes[proto];
14431514Sbrian}
14531514Sbrian
14631518Sbrian/* We support these algorithms, and Req them in the given order */
14755146Sbrianstatic const struct ccp_algorithm * const algorithm[] = {
14831518Sbrian  &DeflateAlgorithm,
14931514Sbrian  &Pred1Algorithm,
15031518Sbrian  &PppdDeflateAlgorithm
15193418Sbrian#ifndef NODES
15267910Sbrian  , &MPPEAlgorithm
15367910Sbrian#endif
15431514Sbrian};
15531514Sbrian
15631962Sbrian#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
15731514Sbrian
15825630Sbrianint
15936285Sbrianccp_ReportStatus(struct cmdargs const *arg)
1606059Samurai{
16178411Sbrian  struct ccp_opt **o;
16236285Sbrian  struct link *l;
16336285Sbrian  struct ccp *ccp;
16478411Sbrian  int f;
16536285Sbrian
16637210Sbrian  l = command_ChooseLink(arg);
16736285Sbrian  ccp = &l->ccp;
16836285Sbrian
16936285Sbrian  prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
17036285Sbrian                State2Nam(ccp->fsm.state));
17146686Sbrian  if (ccp->fsm.state == ST_OPENED) {
17246686Sbrian    prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
17346686Sbrian                  protoname(ccp->my_proto), protoname(ccp->his_proto));
17446686Sbrian    prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
17546686Sbrian                  ccp->uncompout, ccp->compout,
17646686Sbrian                  ccp->compin, ccp->uncompin);
17746686Sbrian  }
17836285Sbrian
17978411Sbrian  if (ccp->in.algorithm != -1)
18078411Sbrian    prompt_Printf(arg->prompt, "\n Input Options:  %s\n",
18178411Sbrian                  (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt));
18278411Sbrian
18378411Sbrian  if (ccp->out.algorithm != -1) {
18478411Sbrian    o = &ccp->out.opt;
18578411Sbrian    for (f = 0; f < ccp->out.algorithm; f++)
18678411Sbrian      if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
18778411Sbrian        o = &(*o)->next;
18878411Sbrian    prompt_Printf(arg->prompt, " Output Options: %s\n",
18978411Sbrian                  (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val));
19078411Sbrian  }
19178411Sbrian
19236285Sbrian  prompt_Printf(arg->prompt, "\n Defaults: ");
19344305Sbrian  prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
19444305Sbrian                " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
19544305Sbrian                ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
19644305Sbrian                ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
19736285Sbrian  prompt_Printf(arg->prompt, "           deflate windows: ");
19836285Sbrian  prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
19936285Sbrian  prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
20093418Sbrian#ifndef NODES
20178411Sbrian  prompt_Printf(arg->prompt, "           MPPE: ");
20278411Sbrian  if (ccp->cfg.mppe.keybits)
20378411Sbrian    prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits);
20478411Sbrian  else
20578411Sbrian    prompt_Printf(arg->prompt, "any bits, ");
20678411Sbrian  switch (ccp->cfg.mppe.state) {
20778411Sbrian  case MPPE_STATEFUL:
20879370Sbrian    prompt_Printf(arg->prompt, "stateful");
20978411Sbrian    break;
21078411Sbrian  case MPPE_STATELESS:
21178411Sbrian    prompt_Printf(arg->prompt, "stateless");
21278411Sbrian    break;
21378411Sbrian  case MPPE_ANYSTATE:
21478411Sbrian    prompt_Printf(arg->prompt, "any state");
21578411Sbrian    break;
21678411Sbrian  }
21778411Sbrian  prompt_Printf(arg->prompt, "%s\n",
21878411Sbrian                ccp->cfg.mppe.required ? ", required" : "");
21978411Sbrian#endif
22078411Sbrian
22178411Sbrian  prompt_Printf(arg->prompt, "\n           DEFLATE:    %s\n",
22236285Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
22336285Sbrian  prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
22436285Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
22536285Sbrian  prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
22636285Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
22793418Sbrian#ifndef NODES
22878411Sbrian  prompt_Printf(arg->prompt, "           MPPE:       %s\n",
22967910Sbrian                command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
23067910Sbrian#endif
23125630Sbrian  return 0;
2326059Samurai}
2336059Samurai
23436285Sbrianvoid
23536285Sbrianccp_SetupCallbacks(struct ccp *ccp)
2366059Samurai{
23736285Sbrian  ccp->fsm.fn = &ccp_Callbacks;
23836285Sbrian  ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
23936285Sbrian  ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
24036285Sbrian  ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
24131539Sbrian}
24231539Sbrian
24331539Sbrianvoid
24436285Sbrianccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
24536285Sbrian         const struct fsm_parent *parent)
24631539Sbrian{
24736285Sbrian  /* Initialise ourselves */
24836285Sbrian
24944305Sbrian  fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
25036285Sbrian           bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
25136285Sbrian
25236285Sbrian  ccp->cfg.deflate.in.winsize = 0;
25336285Sbrian  ccp->cfg.deflate.out.winsize = 15;
25444305Sbrian  ccp->cfg.fsm.timeout = DEF_FSMRETRY;
25544305Sbrian  ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
25644305Sbrian  ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
25736285Sbrian  ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
25836285Sbrian  ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
25936285Sbrian  ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
26093418Sbrian#ifndef NODES
26178411Sbrian  ccp->cfg.mppe.keybits = 0;
26278411Sbrian  ccp->cfg.mppe.state = MPPE_ANYSTATE;
26378411Sbrian  ccp->cfg.mppe.required = 0;
26468906Sbrian  ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
26567910Sbrian#endif
26636285Sbrian
26736285Sbrian  ccp_Setup(ccp);
2686059Samurai}
2696059Samurai
27036285Sbrianvoid
27136285Sbrianccp_Setup(struct ccp *ccp)
27236285Sbrian{
27336285Sbrian  /* Set ourselves up for a startup */
27436285Sbrian  ccp->fsm.open_mode = 0;
27536285Sbrian  ccp->his_proto = ccp->my_proto = -1;
27636285Sbrian  ccp->reset_sent = ccp->last_reset = -1;
27736285Sbrian  ccp->in.algorithm = ccp->out.algorithm = -1;
27836285Sbrian  ccp->in.state = ccp->out.state = NULL;
27994894Sbrian  ccp->in.opt.hdr.id = -1;
28036285Sbrian  ccp->out.opt = NULL;
28136285Sbrian  ccp->his_reject = ccp->my_reject = 0;
28236285Sbrian  ccp->uncompout = ccp->compout = 0;
28336285Sbrian  ccp->uncompin = ccp->compin = 0;
28436285Sbrian}
28536285Sbrian
28678411Sbrian/*
28778411Sbrian * Is ccp *REQUIRED* ?
28878411Sbrian * We ask each of the configured ccp protocols if they're required and
28978411Sbrian * return TRUE if they are.
29078411Sbrian *
29178411Sbrian * It's not possible for the peer to reject a required ccp protocol
29278411Sbrian * without our state machine bringing the supporting lcp layer down.
29378411Sbrian *
29478411Sbrian * If ccp is required but not open, the NCP layer should not push
29578411Sbrian * any data into the link.
29678411Sbrian */
29778411Sbrianint
29878411Sbrianccp_Required(struct ccp *ccp)
29978411Sbrian{
300134789Sbrian  unsigned f;
30178411Sbrian
30278411Sbrian  for (f = 0; f < NALGORITHMS; f++)
30378411Sbrian    if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
30478411Sbrian        (*algorithm[f]->Required)(&ccp->fsm))
30578411Sbrian      return 1;
30678411Sbrian
30778411Sbrian  return 0;
30878411Sbrian}
30978411Sbrian
31079165Sbrian/*
31179165Sbrian * Report whether it's possible to increase a packet's size after
31279165Sbrian * compression (and by how much).
31379165Sbrian */
31479165Sbrianint
31579165Sbrianccp_MTUOverhead(struct ccp *ccp)
31679165Sbrian{
31779396Sbrian  if (ccp->fsm.state == ST_OPENED && ccp->out.algorithm >= 0)
31879165Sbrian    return algorithm[ccp->out.algorithm]->o.MTUOverhead;
31979165Sbrian
32079165Sbrian  return 0;
32179165Sbrian}
32279165Sbrian
3236059Samuraistatic void
32444305SbrianCcpInitRestartCounter(struct fsm *fp, int what)
3256059Samurai{
32636285Sbrian  /* Set fsm timer load */
32736285Sbrian  struct ccp *ccp = fsm2ccp(fp);
32836285Sbrian
32944305Sbrian  fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
33044305Sbrian  switch (what) {
33144305Sbrian    case FSM_REQ_TIMER:
33244305Sbrian      fp->restart = ccp->cfg.fsm.maxreq;
33344305Sbrian      break;
33444305Sbrian    case FSM_TRM_TIMER:
33544305Sbrian      fp->restart = ccp->cfg.fsm.maxtrm;
33644305Sbrian      break;
33744305Sbrian    default:
33844305Sbrian      fp->restart = 1;
33944305Sbrian      break;
34044305Sbrian  }
3416059Samurai}
3426059Samurai
3436059Samuraistatic void
34430715SbrianCcpSendConfigReq(struct fsm *fp)
3456059Samurai{
34636285Sbrian  /* Send config REQ please */
34736285Sbrian  struct ccp *ccp = fsm2ccp(fp);
34836285Sbrian  struct ccp_opt **o;
34936285Sbrian  u_char *cp, buff[100];
350134789Sbrian  unsigned f;
351134789Sbrian  int alloc;
3526059Samurai
35336285Sbrian  cp = buff;
35436285Sbrian  o = &ccp->out.opt;
35536285Sbrian  alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
35636285Sbrian  ccp->my_proto = -1;
35736285Sbrian  ccp->out.algorithm = -1;
35831514Sbrian  for (f = 0; f < NALGORITHMS; f++)
35936285Sbrian    if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
36072025Sbrian        !REJECTED(ccp, algorithm[f]->id) &&
36172025Sbrian        (*algorithm[f]->Usable)(fp)) {
36231514Sbrian
36336285Sbrian      if (!alloc)
36436285Sbrian        for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
365134789Sbrian          if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == (int)f)
36636285Sbrian            break;
36736285Sbrian
36836285Sbrian      if (alloc || *o == NULL) {
369136375Sbrian        if ((*o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt))) == NULL) {
370136375Sbrian	  log_Printf(LogERROR, "%s: Not enough memory for CCP REQ !\n",
371136375Sbrian		     fp->link->name);
372136375Sbrian	  break;
373136375Sbrian	}
37494894Sbrian        (*o)->val.hdr.id = algorithm[f]->id;
37594894Sbrian        (*o)->val.hdr.len = 2;
37636285Sbrian        (*o)->next = NULL;
37736285Sbrian        (*o)->algorithm = f;
37898132Sbrian        (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
37936285Sbrian      }
38036285Sbrian
38194894Sbrian      if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
38236285Sbrian        log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
38336285Sbrian        break;
38436285Sbrian      }
38594894Sbrian      memcpy(cp, &(*o)->val, (*o)->val.hdr.len);
38694894Sbrian      cp += (*o)->val.hdr.len;
38736285Sbrian
38894894Sbrian      ccp->my_proto = (*o)->val.hdr.id;
38936285Sbrian      ccp->out.algorithm = f;
39036285Sbrian
39136285Sbrian      if (alloc)
39236285Sbrian        o = &(*o)->next;
39331514Sbrian    }
39436285Sbrian
39547695Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
3966059Samurai}
3976059Samurai
3986059Samuraivoid
39936285Sbrianccp_SendResetReq(struct fsm *fp)
4006059Samurai{
40136285Sbrian  /* We can't read our input - ask peer to reset */
40236285Sbrian  struct ccp *ccp = fsm2ccp(fp);
40336285Sbrian
40436285Sbrian  ccp->reset_sent = fp->reqid;
40536285Sbrian  ccp->last_reset = -1;
40647695Sbrian  fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
4076059Samurai}
4086059Samurai
4096059Samuraistatic void
410134789SbrianCcpSentTerminateReq(struct fsm *fp __unused)
4116059Samurai{
41236285Sbrian  /* Term REQ just sent by FSM */
4136059Samurai}
4146059Samurai
4156059Samuraistatic void
41636285SbrianCcpSendTerminateAck(struct fsm *fp, u_char id)
4176059Samurai{
41836285Sbrian  /* Send Term ACK please */
41947695Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
4206059Samurai}
4216059Samurai
42278411Sbrianstatic int
42330715SbrianCcpRecvResetReq(struct fsm *fp)
4246059Samurai{
42536285Sbrian  /* Got a reset REQ, reset outgoing dictionary */
42636285Sbrian  struct ccp *ccp = fsm2ccp(fp);
42778411Sbrian  if (ccp->out.state == NULL)
42878411Sbrian    return 1;
42978411Sbrian  return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
4306059Samurai}
4316059Samurai
4326059Samuraistatic void
43330715SbrianCcpLayerStart(struct fsm *fp)
4346059Samurai{
43536285Sbrian  /* We're about to start up ! */
43644305Sbrian  struct ccp *ccp = fsm2ccp(fp);
43744305Sbrian
43837210Sbrian  log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
43944305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
4406059Samurai}
4416059Samurai
4426059Samuraistatic void
44337160SbrianCcpLayerDown(struct fsm *fp)
4446059Samurai{
44537160Sbrian  /* About to come down */
44636285Sbrian  struct ccp *ccp = fsm2ccp(fp);
44736285Sbrian  struct ccp_opt *next;
44836285Sbrian
44937210Sbrian  log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
45036285Sbrian  if (ccp->in.state != NULL) {
45136285Sbrian    (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
45236285Sbrian    ccp->in.state = NULL;
45336285Sbrian    ccp->in.algorithm = -1;
45436285Sbrian  }
45536285Sbrian  if (ccp->out.state != NULL) {
45636285Sbrian    (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
45736285Sbrian    ccp->out.state = NULL;
45836285Sbrian    ccp->out.algorithm = -1;
45936285Sbrian  }
46036285Sbrian  ccp->his_reject = ccp->my_reject = 0;
46198243Sbrian
46236285Sbrian  while (ccp->out.opt) {
46336285Sbrian    next = ccp->out.opt->next;
46436285Sbrian    free(ccp->out.opt);
46536285Sbrian    ccp->out.opt = next;
46636285Sbrian  }
46737160Sbrian  ccp_Setup(ccp);
4686059Samurai}
4696059Samurai
4706059Samuraistatic void
47137160SbrianCcpLayerFinish(struct fsm *fp)
4726059Samurai{
47337160Sbrian  /* We're now down */
47468423Sbrian  struct ccp *ccp = fsm2ccp(fp);
47568423Sbrian  struct ccp_opt *next;
47668423Sbrian
47737210Sbrian  log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
47868423Sbrian
47968423Sbrian  /*
48068423Sbrian   * Nuke options that may be left over from sending a REQ but never
48168423Sbrian   * coming up.
48268423Sbrian   */
48368423Sbrian  while (ccp->out.opt) {
48468423Sbrian    next = ccp->out.opt->next;
48568423Sbrian    free(ccp->out.opt);
48668423Sbrian    ccp->out.opt = next;
48768423Sbrian  }
48878411Sbrian
48978411Sbrian  if (ccp_Required(ccp)) {
49078411Sbrian    if (fp->link->lcp.fsm.state == ST_OPENED)
49178411Sbrian      log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
49278411Sbrian    fsm_Close(&fp->link->lcp.fsm);
49378411Sbrian  }
4946059Samurai}
4956059Samurai
49646828Sbrian/*  Called when CCP has reached the OPEN state */
49736285Sbrianstatic int
49830715SbrianCcpLayerUp(struct fsm *fp)
4996059Samurai{
50036285Sbrian  /* We're now up */
50136285Sbrian  struct ccp *ccp = fsm2ccp(fp);
50268423Sbrian  struct ccp_opt **o;
503134789Sbrian  unsigned f, fail;
50444305Sbrian
50579165Sbrian  for (f = fail = 0; f < NALGORITHMS; f++)
50679165Sbrian    if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
50779165Sbrian        (*algorithm[f]->Required)(&ccp->fsm) &&
508134789Sbrian        (ccp->in.algorithm != (int)f || ccp->out.algorithm != (int)f)) {
50979165Sbrian      /* Blow it all away - we haven't negotiated a required algorithm */
51079165Sbrian      log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
51179165Sbrian                 fp->link->name, protoname(algorithm[f]->id));
51279165Sbrian      fail = 1;
51379165Sbrian    }
51479165Sbrian
51579165Sbrian  if (fail) {
51679165Sbrian    ccp->his_proto = ccp->my_proto = -1;
51779165Sbrian    fsm_Close(fp);
51879165Sbrian    fsm_Close(&fp->link->lcp.fsm);
51979165Sbrian    return 0;
52079165Sbrian  }
52179165Sbrian
52237210Sbrian  log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
52344305Sbrian
52436285Sbrian  if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
525134789Sbrian      ccp->in.algorithm < (int)NALGORITHMS) {
52698132Sbrian    ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
52798132Sbrian      (fp->bundle, &ccp->in.opt);
52836285Sbrian    if (ccp->in.state == NULL) {
52936285Sbrian      log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
53036285Sbrian                fp->link->name, protoname(ccp->his_proto));
53136285Sbrian      ccp->his_proto = ccp->my_proto = -1;
53236285Sbrian      fsm_Close(fp);
53344305Sbrian      return 0;
53436285Sbrian    }
53532246Sbrian  }
5366059Samurai
53768423Sbrian  o = &ccp->out.opt;
538134789Sbrian  if (ccp->out.algorithm > 0)
539134789Sbrian    for (f = 0; f < (unsigned)ccp->out.algorithm; f++)
540134789Sbrian      if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
541134789Sbrian	o = &(*o)->next;
54268423Sbrian
54336285Sbrian  if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
544134789Sbrian      ccp->out.algorithm < (int)NALGORITHMS) {
54598132Sbrian    ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
54698132Sbrian      (fp->bundle, &(*o)->val);
54736285Sbrian    if (ccp->out.state == NULL) {
54836285Sbrian      log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
54936285Sbrian                fp->link->name, protoname(ccp->my_proto));
55036285Sbrian      ccp->his_proto = ccp->my_proto = -1;
55136285Sbrian      fsm_Close(fp);
55244305Sbrian      return 0;
55331514Sbrian    }
55436285Sbrian  }
55531514Sbrian
55644305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
55744305Sbrian
55836285Sbrian  log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
55936285Sbrian            fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
56036285Sbrian            protoname(ccp->his_proto), ccp->his_proto);
56144305Sbrian
56236285Sbrian  return 1;
5636059Samurai}
5646059Samurai
5656059Samuraistatic void
56694894SbrianCcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
56736285Sbrian                struct fsm_decode *dec)
5686059Samurai{
56936285Sbrian  /* Deal with incoming data */
57036285Sbrian  struct ccp *ccp = fsm2ccp(fp);
57194894Sbrian  int f;
57294894Sbrian  const char *disp;
57394894Sbrian  struct fsm_opt *opt;
5746059Samurai
57546310Sbrian  if (mode_type == MODE_REQ)
57646310Sbrian    ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */
57746310Sbrian
578134789Sbrian  while (end >= cp + sizeof(opt->hdr)) {
57994894Sbrian    if ((opt = fsm_readopt(&cp)) == NULL)
58036285Sbrian      break;
58136285Sbrian
58231514Sbrian    for (f = NALGORITHMS-1; f > -1; f--)
58394894Sbrian      if (algorithm[f]->id == opt->hdr.id)
58431514Sbrian        break;
5856059Samurai
58694894Sbrian    disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
58794894Sbrian    if (disp == NULL)
58894894Sbrian      disp = "";
58936285Sbrian
59094894Sbrian    log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
59194894Sbrian               opt->hdr.len, disp);
59236285Sbrian
59331514Sbrian    if (f == -1) {
59431514Sbrian      /* Don't understand that :-( */
59531514Sbrian      if (mode_type == MODE_REQ) {
59694894Sbrian        ccp->my_reject |= (1 << opt->hdr.id);
59794894Sbrian        fsm_rej(dec, opt);
59831514Sbrian      }
59931514Sbrian    } else {
60036285Sbrian      struct ccp_opt *o;
60131514Sbrian
60231034Sbrian      switch (mode_type) {
6036059Samurai      case MODE_REQ:
60494894Sbrian        if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
60572025Sbrian            (*algorithm[f]->Usable)(fp) &&
60636285Sbrian            ccp->in.algorithm == -1) {
60794894Sbrian          memcpy(&ccp->in.opt, opt, opt->hdr.len);
60898132Sbrian          switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
60931514Sbrian          case MODE_REJ:
61094894Sbrian            fsm_rej(dec, &ccp->in.opt);
61131514Sbrian            break;
61231514Sbrian          case MODE_NAK:
61394894Sbrian            fsm_nak(dec, &ccp->in.opt);
61431514Sbrian            break;
61531514Sbrian          case MODE_ACK:
61694894Sbrian            fsm_ack(dec, &ccp->in.opt);
61794894Sbrian            ccp->his_proto = opt->hdr.id;
618134789Sbrian            ccp->in.algorithm = (int)f;		/* This one'll do :-) */
61931514Sbrian            break;
62031514Sbrian          }
62194894Sbrian        } else {
62294894Sbrian          fsm_rej(dec, opt);
62394894Sbrian        }
62494894Sbrian        break;
6256059Samurai      case MODE_NAK:
62636285Sbrian        for (o = ccp->out.opt; o != NULL; o = o->next)
62794894Sbrian          if (o->val.hdr.id == opt->hdr.id)
62836285Sbrian            break;
62936285Sbrian        if (o == NULL)
63067912Sbrian          log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
63167912Sbrian                     " option\n", fp->link->name);
63231514Sbrian        else {
63394894Sbrian          memcpy(&o->val, opt, opt->hdr.len);
63498132Sbrian          if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
63598132Sbrian              MODE_ACK)
63636285Sbrian            ccp->my_proto = algorithm[f]->id;
63736285Sbrian          else {
63894894Sbrian            ccp->his_reject |= (1 << opt->hdr.id);
63994894Sbrian            ccp->my_proto = -1;
64078411Sbrian            if (algorithm[f]->Required(fp)) {
64178411Sbrian              log_Printf(LogWARN, "%s: Cannot understand peers (required)"
64278411Sbrian                         " %s negotiation\n", fp->link->name,
64378411Sbrian                         protoname(algorithm[f]->id));
64478411Sbrian              fsm_Close(&fp->link->lcp.fsm);
64578411Sbrian            }
64636285Sbrian          }
64731514Sbrian        }
64831514Sbrian        break;
6496059Samurai      case MODE_REJ:
65094894Sbrian        ccp->his_reject |= (1 << opt->hdr.id);
65194894Sbrian        ccp->my_proto = -1;
65278411Sbrian        if (algorithm[f]->Required(fp)) {
65378411Sbrian          log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
65478411Sbrian                     fp->link->name, protoname(algorithm[f]->id));
65578411Sbrian          fsm_Close(&fp->link->lcp.fsm);
65678411Sbrian        }
65794894Sbrian        break;
6586059Samurai      }
6596059Samurai    }
6606059Samurai  }
66131514Sbrian
66236285Sbrian  if (mode_type != MODE_NOP) {
66394894Sbrian    fsm_opt_normalise(dec);
66494894Sbrian    if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
66536285Sbrian      if (ccp->in.state == NULL) {
66636285Sbrian        ccp->his_proto = -1;
66736285Sbrian        ccp->in.algorithm = -1;
66836285Sbrian      }
66936285Sbrian    }
67031514Sbrian  }
6716059Samurai}
6726059Samurai
67346686Sbrianextern struct mbuf *
67446686Sbrianccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
6756059Samurai{
67636285Sbrian  /* Got PROTO_CCP from link */
67754912Sbrian  m_settype(bp, MB_CCPIN);
67836285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
67946686Sbrian    fsm_Input(&l->ccp.fsm, bp);
6806059Samurai  else {
68136285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
68236285Sbrian      log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
68346686Sbrian                 l->ccp.fsm.link->name, bundle_PhaseName(bundle));
68454912Sbrian    m_freem(bp);
6856059Samurai  }
68646686Sbrian  return NULL;
6876059Samurai}
68831514Sbrian
68936285Sbrianstatic void
69036285SbrianCcpRecvResetAck(struct fsm *fp, u_char id)
69131514Sbrian{
69236285Sbrian  /* Got a reset ACK, reset incoming dictionary */
69336285Sbrian  struct ccp *ccp = fsm2ccp(fp);
69436285Sbrian
69536285Sbrian  if (ccp->reset_sent != -1) {
69636285Sbrian    if (id != ccp->reset_sent) {
69744650Sbrian      log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
69836285Sbrian                " ignored\n", fp->link->name, id, ccp->reset_sent);
69932381Sbrian      return;
70032381Sbrian    }
70132381Sbrian    /* Whaddaya know - a correct reset ack */
70236285Sbrian  } else if (id == ccp->last_reset)
70336285Sbrian    log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
70444650Sbrian               fp->link->name);
70532381Sbrian  else {
70644650Sbrian    log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
70744650Sbrian               fp->link->name, id);
70832381Sbrian    return;
70932381Sbrian  }
71032381Sbrian
71136285Sbrian  ccp->last_reset = ccp->reset_sent;
71236285Sbrian  ccp->reset_sent = -1;
71336285Sbrian  if (ccp->in.state != NULL)
71436285Sbrian    (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
71531514Sbrian}
71631514Sbrian
71746686Sbrianstatic struct mbuf *
718134789Sbrianccp_LayerPush(struct bundle *b __unused, struct link *l, struct mbuf *bp,
71946686Sbrian              int pri, u_short *proto)
72031514Sbrian{
72178411Sbrian  if (PROTO_COMPRESSIBLE(*proto)) {
72278411Sbrian    if (l->ccp.fsm.state != ST_OPENED) {
72378411Sbrian      if (ccp_Required(&l->ccp)) {
72478411Sbrian        /* The NCP layer shouldn't have let this happen ! */
72578411Sbrian        log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
72678411Sbrian                   " required CCP layer\n", l->name);
72778411Sbrian        m_freem(bp);
72878411Sbrian        bp = NULL;
72978411Sbrian      }
73078411Sbrian    } else if (l->ccp.out.state != NULL) {
73178411Sbrian      bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
73278411Sbrian             (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
73378411Sbrian      switch (*proto) {
73478411Sbrian        case PROTO_ICOMPD:
73578411Sbrian          m_settype(bp, MB_ICOMPDOUT);
73678411Sbrian          break;
73778411Sbrian        case PROTO_COMPD:
73878411Sbrian          m_settype(bp, MB_COMPDOUT);
73978411Sbrian          break;
74078411Sbrian      }
74147695Sbrian    }
74247695Sbrian  }
74346686Sbrian
74446686Sbrian  return bp;
74531514Sbrian}
74631514Sbrian
74746686Sbrianstatic struct mbuf *
748134789Sbrianccp_LayerPull(struct bundle *b __unused, struct link *l, struct mbuf *bp,
749134789Sbrian	      u_short *proto)
75031514Sbrian{
75136285Sbrian  /*
75236285Sbrian   * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
75336285Sbrian   * decompression routines so that the dictionary's updated
75436285Sbrian   */
75546686Sbrian  if (l->ccp.fsm.state == ST_OPENED) {
75636285Sbrian    if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
75736285Sbrian      /* Decompress incoming data */
75846686Sbrian      if (l->ccp.reset_sent != -1)
75936285Sbrian        /* Send another REQ and put the packet in the bit bucket */
76047695Sbrian        fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
76147695Sbrian                   MB_CCPOUT);
76247695Sbrian      else if (l->ccp.in.state != NULL) {
76347695Sbrian        bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
76447695Sbrian               (l->ccp.in.state, &l->ccp, proto, bp);
76547695Sbrian        switch (*proto) {
76647695Sbrian          case PROTO_ICOMPD:
76754912Sbrian            m_settype(bp, MB_ICOMPDIN);
76847695Sbrian            break;
76947695Sbrian          case PROTO_COMPD:
77054912Sbrian            m_settype(bp, MB_COMPDIN);
77147695Sbrian            break;
77247695Sbrian        }
77347695Sbrian        return bp;
77447695Sbrian      }
77554912Sbrian      m_freem(bp);
77636285Sbrian      bp = NULL;
77747061Sbrian    } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
77836285Sbrian      /* Add incoming Network Layer traffic to our dictionary */
77946686Sbrian      (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
78046686Sbrian        (l->ccp.in.state, &l->ccp, *proto, bp);
78199234Sbrian    }
78236285Sbrian  }
78336285Sbrian
78436285Sbrian  return bp;
78531514Sbrian}
78631514Sbrian
78736285Sbrianu_short
78836285Sbrianccp_Proto(struct ccp *ccp)
78931514Sbrian{
79036285Sbrian  return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
79136285Sbrian         PROTO_COMPD : PROTO_ICOMPD;
79231514Sbrian}
79336310Sbrian
79437320Sbrianint
79536310Sbrianccp_SetOpenMode(struct ccp *ccp)
79636310Sbrian{
79736310Sbrian  int f;
79836310Sbrian
79936310Sbrian  for (f = 0; f < CCP_NEG_TOTAL; f++)
80037320Sbrian    if (IsEnabled(ccp->cfg.neg[f])) {
80136310Sbrian      ccp->fsm.open_mode = 0;
80237320Sbrian      return 1;
80337320Sbrian    }
80436310Sbrian
80537320Sbrian  ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
80637320Sbrian
80737320Sbrian  for (f = 0; f < CCP_NEG_TOTAL; f++)
80837320Sbrian    if (IsAccepted(ccp->cfg.neg[f]))
80937320Sbrian      return 1;
81037320Sbrian
81137320Sbrian  return 0;				/* No CCP at all */
81236310Sbrian}
81346686Sbrian
81472025Sbrianint
815134789Sbrianccp_DefaultUsable(struct fsm *fp __unused)
81672025Sbrian{
81772025Sbrian  return 1;
81872025Sbrian}
81972025Sbrian
82078411Sbrianint
821134789Sbrianccp_DefaultRequired(struct fsm *fp __unused)
82278411Sbrian{
82378411Sbrian  return 0;
82478411Sbrian}
82578411Sbrian
82646686Sbrianstruct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
827