Deleted Added
full compact
ccp.c (98132) ccp.c (98243)
1/*-
2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 * Internet Initiative Japan, Inc (IIJ)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
1/*-
2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 * Internet Initiative Japan, Inc (IIJ)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: head/usr.sbin/ppp/ccp.c 98132 2002-06-12 00:33:17Z brian $
28 * $FreeBSD: head/usr.sbin/ppp/ccp.c 98243 2002-06-15 08:03:30Z brian $
29 */
30
31#include <sys/param.h>
32#include <netinet/in.h>
33#include <netinet/in_systm.h>
34#include <netinet/ip.h>
35#include <sys/socket.h>
36#include <sys/un.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h> /* memcpy() on some archs */
41#include <termios.h>
42
43#include "layer.h"
44#include "defs.h"
45#include "command.h"
46#include "mbuf.h"
47#include "log.h"
48#include "timer.h"
49#include "fsm.h"
50#include "proto.h"
51#include "pred.h"
52#include "deflate.h"
53#include "throughput.h"
54#include "iplist.h"
55#include "slcompress.h"
56#include "lqr.h"
57#include "hdlc.h"
58#include "lcp.h"
59#include "ccp.h"
60#include "ncpaddr.h"
61#include "ipcp.h"
62#include "filter.h"
63#include "descriptor.h"
64#include "prompt.h"
65#include "link.h"
66#include "mp.h"
67#include "async.h"
68#include "physical.h"
69#ifndef NORADIUS
70#include "radius.h"
71#endif
72#ifndef NODES
73#include "mppe.h"
74#endif
75#include "ipv6cp.h"
76#include "ncp.h"
77#include "bundle.h"
78
79static void CcpSendConfigReq(struct fsm *);
80static void CcpSentTerminateReq(struct fsm *);
81static void CcpSendTerminateAck(struct fsm *, u_char);
82static void CcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
83 struct fsm_decode *);
84static void CcpLayerStart(struct fsm *);
85static void CcpLayerFinish(struct fsm *);
86static int CcpLayerUp(struct fsm *);
87static void CcpLayerDown(struct fsm *);
88static void CcpInitRestartCounter(struct fsm *, int);
89static int CcpRecvResetReq(struct fsm *);
90static void CcpRecvResetAck(struct fsm *, u_char);
91
92static struct fsm_callbacks ccp_Callbacks = {
93 CcpLayerUp,
94 CcpLayerDown,
95 CcpLayerStart,
96 CcpLayerFinish,
97 CcpInitRestartCounter,
98 CcpSendConfigReq,
99 CcpSentTerminateReq,
100 CcpSendTerminateAck,
101 CcpDecodeConfig,
102 CcpRecvResetReq,
103 CcpRecvResetAck
104};
105
106static const char * const ccp_TimerNames[] =
107 {"CCP restart", "CCP openmode", "CCP stopped"};
108
109static const char *
110protoname(int proto)
111{
112 static char const * const cftypes[] = {
113 /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
114 "OUI", /* 0: OUI */
115 "PRED1", /* 1: Predictor type 1 */
116 "PRED2", /* 2: Predictor type 2 */
117 "PUDDLE", /* 3: Puddle Jumber */
118 NULL, NULL, NULL, NULL, NULL, NULL,
119 NULL, NULL, NULL, NULL, NULL, NULL,
120 "HWPPC", /* 16: Hewlett-Packard PPC */
121 "STAC", /* 17: Stac Electronics LZS (rfc1974) */
122 "MPPE", /* 18: Microsoft PPC (rfc2118) and */
123 /* Microsoft PPE (draft-ietf-pppext-mppe) */
124 "GAND", /* 19: Gandalf FZA (rfc1993) */
125 "V42BIS", /* 20: ARG->DATA.42bis compression */
126 "BSD", /* 21: BSD LZW Compress */
127 NULL,
128 "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */
129 "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
130 /* 24: Deflate (according to pppd-2.3.*) */
131 "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */
132 "DEFLATE", /* 26: Deflate (rfc1979) */
133 };
134
135 if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes ||
136 cftypes[proto] == NULL) {
137 if (proto == -1)
138 return "none";
139 return HexStr(proto, NULL, 0);
140 }
141
142 return cftypes[proto];
143}
144
145/* We support these algorithms, and Req them in the given order */
146static const struct ccp_algorithm * const algorithm[] = {
147 &DeflateAlgorithm,
148 &Pred1Algorithm,
149 &PppdDeflateAlgorithm
150#ifndef NODES
151 , &MPPEAlgorithm
152#endif
153};
154
155#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
156
157int
158ccp_ReportStatus(struct cmdargs const *arg)
159{
160 struct ccp_opt **o;
161 struct link *l;
162 struct ccp *ccp;
163 int f;
164
165 l = command_ChooseLink(arg);
166 ccp = &l->ccp;
167
168 prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
169 State2Nam(ccp->fsm.state));
170 if (ccp->fsm.state == ST_OPENED) {
171 prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
172 protoname(ccp->my_proto), protoname(ccp->his_proto));
173 prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n",
174 ccp->uncompout, ccp->compout,
175 ccp->compin, ccp->uncompin);
176 }
177
178 if (ccp->in.algorithm != -1)
179 prompt_Printf(arg->prompt, "\n Input Options: %s\n",
180 (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt));
181
182 if (ccp->out.algorithm != -1) {
183 o = &ccp->out.opt;
184 for (f = 0; f < ccp->out.algorithm; f++)
185 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
186 o = &(*o)->next;
187 prompt_Printf(arg->prompt, " Output Options: %s\n",
188 (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val));
189 }
190
191 prompt_Printf(arg->prompt, "\n Defaults: ");
192 prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
193 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
194 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
195 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
196 prompt_Printf(arg->prompt, " deflate windows: ");
197 prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
198 prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
199#ifndef NODES
200 prompt_Printf(arg->prompt, " MPPE: ");
201 if (ccp->cfg.mppe.keybits)
202 prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits);
203 else
204 prompt_Printf(arg->prompt, "any bits, ");
205 switch (ccp->cfg.mppe.state) {
206 case MPPE_STATEFUL:
207 prompt_Printf(arg->prompt, "stateful");
208 break;
209 case MPPE_STATELESS:
210 prompt_Printf(arg->prompt, "stateless");
211 break;
212 case MPPE_ANYSTATE:
213 prompt_Printf(arg->prompt, "any state");
214 break;
215 }
216 prompt_Printf(arg->prompt, "%s\n",
217 ccp->cfg.mppe.required ? ", required" : "");
218#endif
219
220 prompt_Printf(arg->prompt, "\n DEFLATE: %s\n",
221 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
222 prompt_Printf(arg->prompt, " PREDICTOR1: %s\n",
223 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
224 prompt_Printf(arg->prompt, " DEFLATE24: %s\n",
225 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
226#ifndef NODES
227 prompt_Printf(arg->prompt, " MPPE: %s\n",
228 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
229#endif
230 return 0;
231}
232
233void
234ccp_SetupCallbacks(struct ccp *ccp)
235{
236 ccp->fsm.fn = &ccp_Callbacks;
237 ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
238 ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
239 ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
240}
241
242void
243ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
244 const struct fsm_parent *parent)
245{
246 /* Initialise ourselves */
247
248 fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
249 bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
250
251 ccp->cfg.deflate.in.winsize = 0;
252 ccp->cfg.deflate.out.winsize = 15;
253 ccp->cfg.fsm.timeout = DEF_FSMRETRY;
254 ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
255 ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
256 ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
257 ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
258 ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
259#ifndef NODES
260 ccp->cfg.mppe.keybits = 0;
261 ccp->cfg.mppe.state = MPPE_ANYSTATE;
262 ccp->cfg.mppe.required = 0;
263 ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
264#endif
265
266 ccp_Setup(ccp);
267}
268
269void
270ccp_Setup(struct ccp *ccp)
271{
272 /* Set ourselves up for a startup */
273 ccp->fsm.open_mode = 0;
274 ccp->his_proto = ccp->my_proto = -1;
275 ccp->reset_sent = ccp->last_reset = -1;
276 ccp->in.algorithm = ccp->out.algorithm = -1;
277 ccp->in.state = ccp->out.state = NULL;
278 ccp->in.opt.hdr.id = -1;
279 ccp->out.opt = NULL;
280 ccp->his_reject = ccp->my_reject = 0;
281 ccp->uncompout = ccp->compout = 0;
282 ccp->uncompin = ccp->compin = 0;
283}
284
285/*
286 * Is ccp *REQUIRED* ?
287 * We ask each of the configured ccp protocols if they're required and
288 * return TRUE if they are.
289 *
290 * It's not possible for the peer to reject a required ccp protocol
291 * without our state machine bringing the supporting lcp layer down.
292 *
293 * If ccp is required but not open, the NCP layer should not push
294 * any data into the link.
295 */
296int
297ccp_Required(struct ccp *ccp)
298{
299 int f;
300
301 for (f = 0; f < NALGORITHMS; f++)
302 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
303 (*algorithm[f]->Required)(&ccp->fsm))
304 return 1;
305
306 return 0;
307}
308
309/*
310 * Report whether it's possible to increase a packet's size after
311 * compression (and by how much).
312 */
313int
314ccp_MTUOverhead(struct ccp *ccp)
315{
316 if (ccp->fsm.state == ST_OPENED && ccp->out.algorithm >= 0)
317 return algorithm[ccp->out.algorithm]->o.MTUOverhead;
318
319 return 0;
320}
321
322static void
323CcpInitRestartCounter(struct fsm *fp, int what)
324{
325 /* Set fsm timer load */
326 struct ccp *ccp = fsm2ccp(fp);
327
328 fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
329 switch (what) {
330 case FSM_REQ_TIMER:
331 fp->restart = ccp->cfg.fsm.maxreq;
332 break;
333 case FSM_TRM_TIMER:
334 fp->restart = ccp->cfg.fsm.maxtrm;
335 break;
336 default:
337 fp->restart = 1;
338 break;
339 }
340}
341
342static void
343CcpSendConfigReq(struct fsm *fp)
344{
345 /* Send config REQ please */
346 struct ccp *ccp = fsm2ccp(fp);
347 struct ccp_opt **o;
348 u_char *cp, buff[100];
349 int f, alloc;
350
351 cp = buff;
352 o = &ccp->out.opt;
353 alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
354 ccp->my_proto = -1;
355 ccp->out.algorithm = -1;
356 for (f = 0; f < NALGORITHMS; f++)
357 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
358 !REJECTED(ccp, algorithm[f]->id) &&
359 (*algorithm[f]->Usable)(fp)) {
360
361 if (!alloc)
362 for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
363 if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == f)
364 break;
365
366 if (alloc || *o == NULL) {
367 *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
368 (*o)->val.hdr.id = algorithm[f]->id;
369 (*o)->val.hdr.len = 2;
370 (*o)->next = NULL;
371 (*o)->algorithm = f;
372 (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
373 }
374
375 if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
376 log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
377 break;
378 }
379 memcpy(cp, &(*o)->val, (*o)->val.hdr.len);
380 cp += (*o)->val.hdr.len;
381
382 ccp->my_proto = (*o)->val.hdr.id;
383 ccp->out.algorithm = f;
384
385 if (alloc)
386 o = &(*o)->next;
387 }
388
389 fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
390}
391
392void
393ccp_SendResetReq(struct fsm *fp)
394{
395 /* We can't read our input - ask peer to reset */
396 struct ccp *ccp = fsm2ccp(fp);
397
398 ccp->reset_sent = fp->reqid;
399 ccp->last_reset = -1;
400 fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
401}
402
403static void
404CcpSentTerminateReq(struct fsm *fp)
405{
406 /* Term REQ just sent by FSM */
407}
408
409static void
410CcpSendTerminateAck(struct fsm *fp, u_char id)
411{
412 /* Send Term ACK please */
413 fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
414}
415
416static int
417CcpRecvResetReq(struct fsm *fp)
418{
419 /* Got a reset REQ, reset outgoing dictionary */
420 struct ccp *ccp = fsm2ccp(fp);
421 if (ccp->out.state == NULL)
422 return 1;
423 return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
424}
425
426static void
427CcpLayerStart(struct fsm *fp)
428{
429 /* We're about to start up ! */
430 struct ccp *ccp = fsm2ccp(fp);
431
432 log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
433 fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
434}
435
436static void
437CcpLayerDown(struct fsm *fp)
438{
439 /* About to come down */
440 struct ccp *ccp = fsm2ccp(fp);
441 struct ccp_opt *next;
442
443 log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
444 if (ccp->in.state != NULL) {
445 (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
446 ccp->in.state = NULL;
447 ccp->in.algorithm = -1;
448 }
449 if (ccp->out.state != NULL) {
450 (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
451 ccp->out.state = NULL;
452 ccp->out.algorithm = -1;
453 }
454 ccp->his_reject = ccp->my_reject = 0;
29 */
30
31#include <sys/param.h>
32#include <netinet/in.h>
33#include <netinet/in_systm.h>
34#include <netinet/ip.h>
35#include <sys/socket.h>
36#include <sys/un.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h> /* memcpy() on some archs */
41#include <termios.h>
42
43#include "layer.h"
44#include "defs.h"
45#include "command.h"
46#include "mbuf.h"
47#include "log.h"
48#include "timer.h"
49#include "fsm.h"
50#include "proto.h"
51#include "pred.h"
52#include "deflate.h"
53#include "throughput.h"
54#include "iplist.h"
55#include "slcompress.h"
56#include "lqr.h"
57#include "hdlc.h"
58#include "lcp.h"
59#include "ccp.h"
60#include "ncpaddr.h"
61#include "ipcp.h"
62#include "filter.h"
63#include "descriptor.h"
64#include "prompt.h"
65#include "link.h"
66#include "mp.h"
67#include "async.h"
68#include "physical.h"
69#ifndef NORADIUS
70#include "radius.h"
71#endif
72#ifndef NODES
73#include "mppe.h"
74#endif
75#include "ipv6cp.h"
76#include "ncp.h"
77#include "bundle.h"
78
79static void CcpSendConfigReq(struct fsm *);
80static void CcpSentTerminateReq(struct fsm *);
81static void CcpSendTerminateAck(struct fsm *, u_char);
82static void CcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
83 struct fsm_decode *);
84static void CcpLayerStart(struct fsm *);
85static void CcpLayerFinish(struct fsm *);
86static int CcpLayerUp(struct fsm *);
87static void CcpLayerDown(struct fsm *);
88static void CcpInitRestartCounter(struct fsm *, int);
89static int CcpRecvResetReq(struct fsm *);
90static void CcpRecvResetAck(struct fsm *, u_char);
91
92static struct fsm_callbacks ccp_Callbacks = {
93 CcpLayerUp,
94 CcpLayerDown,
95 CcpLayerStart,
96 CcpLayerFinish,
97 CcpInitRestartCounter,
98 CcpSendConfigReq,
99 CcpSentTerminateReq,
100 CcpSendTerminateAck,
101 CcpDecodeConfig,
102 CcpRecvResetReq,
103 CcpRecvResetAck
104};
105
106static const char * const ccp_TimerNames[] =
107 {"CCP restart", "CCP openmode", "CCP stopped"};
108
109static const char *
110protoname(int proto)
111{
112 static char const * const cftypes[] = {
113 /* Check out the latest ``Compression Control Protocol'' rfc (1962) */
114 "OUI", /* 0: OUI */
115 "PRED1", /* 1: Predictor type 1 */
116 "PRED2", /* 2: Predictor type 2 */
117 "PUDDLE", /* 3: Puddle Jumber */
118 NULL, NULL, NULL, NULL, NULL, NULL,
119 NULL, NULL, NULL, NULL, NULL, NULL,
120 "HWPPC", /* 16: Hewlett-Packard PPC */
121 "STAC", /* 17: Stac Electronics LZS (rfc1974) */
122 "MPPE", /* 18: Microsoft PPC (rfc2118) and */
123 /* Microsoft PPE (draft-ietf-pppext-mppe) */
124 "GAND", /* 19: Gandalf FZA (rfc1993) */
125 "V42BIS", /* 20: ARG->DATA.42bis compression */
126 "BSD", /* 21: BSD LZW Compress */
127 NULL,
128 "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */
129 "MAGNALINK/DEFLATE",/* 24: Magnalink Variable Resource (rfc1975) */
130 /* 24: Deflate (according to pppd-2.3.*) */
131 "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */
132 "DEFLATE", /* 26: Deflate (rfc1979) */
133 };
134
135 if (proto < 0 || proto > sizeof cftypes / sizeof *cftypes ||
136 cftypes[proto] == NULL) {
137 if (proto == -1)
138 return "none";
139 return HexStr(proto, NULL, 0);
140 }
141
142 return cftypes[proto];
143}
144
145/* We support these algorithms, and Req them in the given order */
146static const struct ccp_algorithm * const algorithm[] = {
147 &DeflateAlgorithm,
148 &Pred1Algorithm,
149 &PppdDeflateAlgorithm
150#ifndef NODES
151 , &MPPEAlgorithm
152#endif
153};
154
155#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
156
157int
158ccp_ReportStatus(struct cmdargs const *arg)
159{
160 struct ccp_opt **o;
161 struct link *l;
162 struct ccp *ccp;
163 int f;
164
165 l = command_ChooseLink(arg);
166 ccp = &l->ccp;
167
168 prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
169 State2Nam(ccp->fsm.state));
170 if (ccp->fsm.state == ST_OPENED) {
171 prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
172 protoname(ccp->my_proto), protoname(ccp->his_proto));
173 prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n",
174 ccp->uncompout, ccp->compout,
175 ccp->compin, ccp->uncompin);
176 }
177
178 if (ccp->in.algorithm != -1)
179 prompt_Printf(arg->prompt, "\n Input Options: %s\n",
180 (*algorithm[ccp->in.algorithm]->Disp)(&ccp->in.opt));
181
182 if (ccp->out.algorithm != -1) {
183 o = &ccp->out.opt;
184 for (f = 0; f < ccp->out.algorithm; f++)
185 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
186 o = &(*o)->next;
187 prompt_Printf(arg->prompt, " Output Options: %s\n",
188 (*algorithm[ccp->out.algorithm]->Disp)(&(*o)->val));
189 }
190
191 prompt_Printf(arg->prompt, "\n Defaults: ");
192 prompt_Printf(arg->prompt, "FSM retry = %us, max %u Config"
193 " REQ%s, %u Term REQ%s\n", ccp->cfg.fsm.timeout,
194 ccp->cfg.fsm.maxreq, ccp->cfg.fsm.maxreq == 1 ? "" : "s",
195 ccp->cfg.fsm.maxtrm, ccp->cfg.fsm.maxtrm == 1 ? "" : "s");
196 prompt_Printf(arg->prompt, " deflate windows: ");
197 prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
198 prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
199#ifndef NODES
200 prompt_Printf(arg->prompt, " MPPE: ");
201 if (ccp->cfg.mppe.keybits)
202 prompt_Printf(arg->prompt, "%d bits, ", ccp->cfg.mppe.keybits);
203 else
204 prompt_Printf(arg->prompt, "any bits, ");
205 switch (ccp->cfg.mppe.state) {
206 case MPPE_STATEFUL:
207 prompt_Printf(arg->prompt, "stateful");
208 break;
209 case MPPE_STATELESS:
210 prompt_Printf(arg->prompt, "stateless");
211 break;
212 case MPPE_ANYSTATE:
213 prompt_Printf(arg->prompt, "any state");
214 break;
215 }
216 prompt_Printf(arg->prompt, "%s\n",
217 ccp->cfg.mppe.required ? ", required" : "");
218#endif
219
220 prompt_Printf(arg->prompt, "\n DEFLATE: %s\n",
221 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
222 prompt_Printf(arg->prompt, " PREDICTOR1: %s\n",
223 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
224 prompt_Printf(arg->prompt, " DEFLATE24: %s\n",
225 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
226#ifndef NODES
227 prompt_Printf(arg->prompt, " MPPE: %s\n",
228 command_ShowNegval(ccp->cfg.neg[CCP_NEG_MPPE]));
229#endif
230 return 0;
231}
232
233void
234ccp_SetupCallbacks(struct ccp *ccp)
235{
236 ccp->fsm.fn = &ccp_Callbacks;
237 ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
238 ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
239 ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
240}
241
242void
243ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
244 const struct fsm_parent *parent)
245{
246 /* Initialise ourselves */
247
248 fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, LogCCP,
249 bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
250
251 ccp->cfg.deflate.in.winsize = 0;
252 ccp->cfg.deflate.out.winsize = 15;
253 ccp->cfg.fsm.timeout = DEF_FSMRETRY;
254 ccp->cfg.fsm.maxreq = DEF_FSMTRIES;
255 ccp->cfg.fsm.maxtrm = DEF_FSMTRIES;
256 ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
257 ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
258 ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
259#ifndef NODES
260 ccp->cfg.mppe.keybits = 0;
261 ccp->cfg.mppe.state = MPPE_ANYSTATE;
262 ccp->cfg.mppe.required = 0;
263 ccp->cfg.neg[CCP_NEG_MPPE] = NEG_ENABLED|NEG_ACCEPTED;
264#endif
265
266 ccp_Setup(ccp);
267}
268
269void
270ccp_Setup(struct ccp *ccp)
271{
272 /* Set ourselves up for a startup */
273 ccp->fsm.open_mode = 0;
274 ccp->his_proto = ccp->my_proto = -1;
275 ccp->reset_sent = ccp->last_reset = -1;
276 ccp->in.algorithm = ccp->out.algorithm = -1;
277 ccp->in.state = ccp->out.state = NULL;
278 ccp->in.opt.hdr.id = -1;
279 ccp->out.opt = NULL;
280 ccp->his_reject = ccp->my_reject = 0;
281 ccp->uncompout = ccp->compout = 0;
282 ccp->uncompin = ccp->compin = 0;
283}
284
285/*
286 * Is ccp *REQUIRED* ?
287 * We ask each of the configured ccp protocols if they're required and
288 * return TRUE if they are.
289 *
290 * It's not possible for the peer to reject a required ccp protocol
291 * without our state machine bringing the supporting lcp layer down.
292 *
293 * If ccp is required but not open, the NCP layer should not push
294 * any data into the link.
295 */
296int
297ccp_Required(struct ccp *ccp)
298{
299 int f;
300
301 for (f = 0; f < NALGORITHMS; f++)
302 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
303 (*algorithm[f]->Required)(&ccp->fsm))
304 return 1;
305
306 return 0;
307}
308
309/*
310 * Report whether it's possible to increase a packet's size after
311 * compression (and by how much).
312 */
313int
314ccp_MTUOverhead(struct ccp *ccp)
315{
316 if (ccp->fsm.state == ST_OPENED && ccp->out.algorithm >= 0)
317 return algorithm[ccp->out.algorithm]->o.MTUOverhead;
318
319 return 0;
320}
321
322static void
323CcpInitRestartCounter(struct fsm *fp, int what)
324{
325 /* Set fsm timer load */
326 struct ccp *ccp = fsm2ccp(fp);
327
328 fp->FsmTimer.load = ccp->cfg.fsm.timeout * SECTICKS;
329 switch (what) {
330 case FSM_REQ_TIMER:
331 fp->restart = ccp->cfg.fsm.maxreq;
332 break;
333 case FSM_TRM_TIMER:
334 fp->restart = ccp->cfg.fsm.maxtrm;
335 break;
336 default:
337 fp->restart = 1;
338 break;
339 }
340}
341
342static void
343CcpSendConfigReq(struct fsm *fp)
344{
345 /* Send config REQ please */
346 struct ccp *ccp = fsm2ccp(fp);
347 struct ccp_opt **o;
348 u_char *cp, buff[100];
349 int f, alloc;
350
351 cp = buff;
352 o = &ccp->out.opt;
353 alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
354 ccp->my_proto = -1;
355 ccp->out.algorithm = -1;
356 for (f = 0; f < NALGORITHMS; f++)
357 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
358 !REJECTED(ccp, algorithm[f]->id) &&
359 (*algorithm[f]->Usable)(fp)) {
360
361 if (!alloc)
362 for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
363 if ((*o)->val.hdr.id == algorithm[f]->id && (*o)->algorithm == f)
364 break;
365
366 if (alloc || *o == NULL) {
367 *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
368 (*o)->val.hdr.id = algorithm[f]->id;
369 (*o)->val.hdr.len = 2;
370 (*o)->next = NULL;
371 (*o)->algorithm = f;
372 (*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
373 }
374
375 if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
376 log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
377 break;
378 }
379 memcpy(cp, &(*o)->val, (*o)->val.hdr.len);
380 cp += (*o)->val.hdr.len;
381
382 ccp->my_proto = (*o)->val.hdr.id;
383 ccp->out.algorithm = f;
384
385 if (alloc)
386 o = &(*o)->next;
387 }
388
389 fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff, MB_CCPOUT);
390}
391
392void
393ccp_SendResetReq(struct fsm *fp)
394{
395 /* We can't read our input - ask peer to reset */
396 struct ccp *ccp = fsm2ccp(fp);
397
398 ccp->reset_sent = fp->reqid;
399 ccp->last_reset = -1;
400 fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0, MB_CCPOUT);
401}
402
403static void
404CcpSentTerminateReq(struct fsm *fp)
405{
406 /* Term REQ just sent by FSM */
407}
408
409static void
410CcpSendTerminateAck(struct fsm *fp, u_char id)
411{
412 /* Send Term ACK please */
413 fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_CCPOUT);
414}
415
416static int
417CcpRecvResetReq(struct fsm *fp)
418{
419 /* Got a reset REQ, reset outgoing dictionary */
420 struct ccp *ccp = fsm2ccp(fp);
421 if (ccp->out.state == NULL)
422 return 1;
423 return (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
424}
425
426static void
427CcpLayerStart(struct fsm *fp)
428{
429 /* We're about to start up ! */
430 struct ccp *ccp = fsm2ccp(fp);
431
432 log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
433 fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
434}
435
436static void
437CcpLayerDown(struct fsm *fp)
438{
439 /* About to come down */
440 struct ccp *ccp = fsm2ccp(fp);
441 struct ccp_opt *next;
442
443 log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
444 if (ccp->in.state != NULL) {
445 (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
446 ccp->in.state = NULL;
447 ccp->in.algorithm = -1;
448 }
449 if (ccp->out.state != NULL) {
450 (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
451 ccp->out.state = NULL;
452 ccp->out.algorithm = -1;
453 }
454 ccp->his_reject = ccp->my_reject = 0;
455
455
456 while (ccp->out.opt) {
457 next = ccp->out.opt->next;
458 free(ccp->out.opt);
459 ccp->out.opt = next;
460 }
461 ccp_Setup(ccp);
462}
463
464static void
465CcpLayerFinish(struct fsm *fp)
466{
467 /* We're now down */
468 struct ccp *ccp = fsm2ccp(fp);
469 struct ccp_opt *next;
470
471 log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
472
473 /*
474 * Nuke options that may be left over from sending a REQ but never
475 * coming up.
476 */
477 while (ccp->out.opt) {
478 next = ccp->out.opt->next;
479 free(ccp->out.opt);
480 ccp->out.opt = next;
481 }
482
483 if (ccp_Required(ccp)) {
484 if (fp->link->lcp.fsm.state == ST_OPENED)
485 log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
486 fsm_Close(&fp->link->lcp.fsm);
487 }
488}
489
490/* Called when CCP has reached the OPEN state */
491static int
492CcpLayerUp(struct fsm *fp)
493{
494 /* We're now up */
495 struct ccp *ccp = fsm2ccp(fp);
496 struct ccp_opt **o;
497 int f, fail;
498
499 for (f = fail = 0; f < NALGORITHMS; f++)
500 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
501 (*algorithm[f]->Required)(&ccp->fsm) &&
502 (ccp->in.algorithm != f || ccp->out.algorithm != f)) {
503 /* Blow it all away - we haven't negotiated a required algorithm */
504 log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
505 fp->link->name, protoname(algorithm[f]->id));
506 fail = 1;
507 }
508
509 if (fail) {
510 ccp->his_proto = ccp->my_proto = -1;
511 fsm_Close(fp);
512 fsm_Close(&fp->link->lcp.fsm);
513 return 0;
514 }
515
516 log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
517
518 if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
519 ccp->in.algorithm < NALGORITHMS) {
520 ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
521 (fp->bundle, &ccp->in.opt);
522 if (ccp->in.state == NULL) {
523 log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
524 fp->link->name, protoname(ccp->his_proto));
525 ccp->his_proto = ccp->my_proto = -1;
526 fsm_Close(fp);
527 return 0;
528 }
529 }
530
531 o = &ccp->out.opt;
532 for (f = 0; f < ccp->out.algorithm; f++)
533 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
534 o = &(*o)->next;
535
536 if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
537 ccp->out.algorithm < NALGORITHMS) {
538 ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
539 (fp->bundle, &(*o)->val);
540 if (ccp->out.state == NULL) {
541 log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
542 fp->link->name, protoname(ccp->my_proto));
543 ccp->his_proto = ccp->my_proto = -1;
544 fsm_Close(fp);
545 return 0;
546 }
547 }
548
549 fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
550
551 log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
552 fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
553 protoname(ccp->his_proto), ccp->his_proto);
554
555 return 1;
556}
557
558static void
559CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
560 struct fsm_decode *dec)
561{
562 /* Deal with incoming data */
563 struct ccp *ccp = fsm2ccp(fp);
564 int f;
565 const char *disp;
566 struct fsm_opt *opt;
567
568 if (mode_type == MODE_REQ)
569 ccp->in.algorithm = -1; /* In case we've received two REQs in a row */
570
571 while (end - cp >= sizeof(opt->hdr)) {
572 if ((opt = fsm_readopt(&cp)) == NULL)
573 break;
574
575 for (f = NALGORITHMS-1; f > -1; f--)
576 if (algorithm[f]->id == opt->hdr.id)
577 break;
578
579 disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
580 if (disp == NULL)
581 disp = "";
582
583 log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
584 opt->hdr.len, disp);
585
586 if (f == -1) {
587 /* Don't understand that :-( */
588 if (mode_type == MODE_REQ) {
589 ccp->my_reject |= (1 << opt->hdr.id);
590 fsm_rej(dec, opt);
591 }
592 } else {
593 struct ccp_opt *o;
594
595 switch (mode_type) {
596 case MODE_REQ:
597 if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
598 (*algorithm[f]->Usable)(fp) &&
599 ccp->in.algorithm == -1) {
600 memcpy(&ccp->in.opt, opt, opt->hdr.len);
601 switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
602 case MODE_REJ:
603 fsm_rej(dec, &ccp->in.opt);
604 break;
605 case MODE_NAK:
606 fsm_nak(dec, &ccp->in.opt);
607 break;
608 case MODE_ACK:
609 fsm_ack(dec, &ccp->in.opt);
610 ccp->his_proto = opt->hdr.id;
611 ccp->in.algorithm = f; /* This one'll do :-) */
612 break;
613 }
614 } else {
615 fsm_rej(dec, opt);
616 }
617 break;
618 case MODE_NAK:
619 for (o = ccp->out.opt; o != NULL; o = o->next)
620 if (o->val.hdr.id == opt->hdr.id)
621 break;
622 if (o == NULL)
623 log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
624 " option\n", fp->link->name);
625 else {
626 memcpy(&o->val, opt, opt->hdr.len);
627 if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
628 MODE_ACK)
629 ccp->my_proto = algorithm[f]->id;
630 else {
631 ccp->his_reject |= (1 << opt->hdr.id);
632 ccp->my_proto = -1;
633 if (algorithm[f]->Required(fp)) {
634 log_Printf(LogWARN, "%s: Cannot understand peers (required)"
635 " %s negotiation\n", fp->link->name,
636 protoname(algorithm[f]->id));
637 fsm_Close(&fp->link->lcp.fsm);
638 }
639 }
640 }
641 break;
642 case MODE_REJ:
643 ccp->his_reject |= (1 << opt->hdr.id);
644 ccp->my_proto = -1;
645 if (algorithm[f]->Required(fp)) {
646 log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
647 fp->link->name, protoname(algorithm[f]->id));
648 fsm_Close(&fp->link->lcp.fsm);
649 }
650 break;
651 }
652 }
653 }
654
655 if (mode_type != MODE_NOP) {
656 fsm_opt_normalise(dec);
657 if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
658 if (ccp->in.state == NULL) {
659 ccp->his_proto = -1;
660 ccp->in.algorithm = -1;
661 }
662 }
663 }
664}
665
666extern struct mbuf *
667ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
668{
669 /* Got PROTO_CCP from link */
670 m_settype(bp, MB_CCPIN);
671 if (bundle_Phase(bundle) == PHASE_NETWORK)
672 fsm_Input(&l->ccp.fsm, bp);
673 else {
674 if (bundle_Phase(bundle) < PHASE_NETWORK)
675 log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
676 l->ccp.fsm.link->name, bundle_PhaseName(bundle));
677 m_freem(bp);
678 }
679 return NULL;
680}
681
682static void
683CcpRecvResetAck(struct fsm *fp, u_char id)
684{
685 /* Got a reset ACK, reset incoming dictionary */
686 struct ccp *ccp = fsm2ccp(fp);
687
688 if (ccp->reset_sent != -1) {
689 if (id != ccp->reset_sent) {
690 log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
691 " ignored\n", fp->link->name, id, ccp->reset_sent);
692 return;
693 }
694 /* Whaddaya know - a correct reset ack */
695 } else if (id == ccp->last_reset)
696 log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
697 fp->link->name);
698 else {
699 log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
700 fp->link->name, id);
701 return;
702 }
703
704 ccp->last_reset = ccp->reset_sent;
705 ccp->reset_sent = -1;
706 if (ccp->in.state != NULL)
707 (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
708}
709
710static struct mbuf *
711ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
712 int pri, u_short *proto)
713{
714 if (PROTO_COMPRESSIBLE(*proto)) {
715 if (l->ccp.fsm.state != ST_OPENED) {
716 if (ccp_Required(&l->ccp)) {
717 /* The NCP layer shouldn't have let this happen ! */
718 log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
719 " required CCP layer\n", l->name);
720 m_freem(bp);
721 bp = NULL;
722 }
723 } else if (l->ccp.out.state != NULL) {
724 bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
725 (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
726 switch (*proto) {
727 case PROTO_ICOMPD:
728 m_settype(bp, MB_ICOMPDOUT);
729 break;
730 case PROTO_COMPD:
731 m_settype(bp, MB_COMPDOUT);
732 break;
733 }
734 }
735 }
736
737 return bp;
738}
739
740static struct mbuf *
741ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
742{
743 /*
744 * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
745 * decompression routines so that the dictionary's updated
746 */
747 if (l->ccp.fsm.state == ST_OPENED) {
748 if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
749 log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n",
750 *proto == PROTO_ICOMPD ? "I" : "");
751 /* Decompress incoming data */
752 if (l->ccp.reset_sent != -1)
753 /* Send another REQ and put the packet in the bit bucket */
754 fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
755 MB_CCPOUT);
756 else if (l->ccp.in.state != NULL) {
757 bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
758 (l->ccp.in.state, &l->ccp, proto, bp);
759 switch (*proto) {
760 case PROTO_ICOMPD:
761 m_settype(bp, MB_ICOMPDIN);
762 break;
763 case PROTO_COMPD:
764 m_settype(bp, MB_COMPDIN);
765 break;
766 }
767 return bp;
768 }
769 m_freem(bp);
770 bp = NULL;
771 } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
772 log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n");
773 /* Add incoming Network Layer traffic to our dictionary */
774 (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
775 (l->ccp.in.state, &l->ccp, *proto, bp);
776 } else
777 log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n");
778 }
779
780 return bp;
781}
782
783u_short
784ccp_Proto(struct ccp *ccp)
785{
786 return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
787 PROTO_COMPD : PROTO_ICOMPD;
788}
789
790int
791ccp_SetOpenMode(struct ccp *ccp)
792{
793 int f;
794
795 for (f = 0; f < CCP_NEG_TOTAL; f++)
796 if (IsEnabled(ccp->cfg.neg[f])) {
797 ccp->fsm.open_mode = 0;
798 return 1;
799 }
800
801 ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */
802
803 for (f = 0; f < CCP_NEG_TOTAL; f++)
804 if (IsAccepted(ccp->cfg.neg[f]))
805 return 1;
806
807 return 0; /* No CCP at all */
808}
809
810int
811ccp_DefaultUsable(struct fsm *fp)
812{
813 return 1;
814}
815
816int
817ccp_DefaultRequired(struct fsm *fp)
818{
819 return 0;
820}
821
822struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };
456 while (ccp->out.opt) {
457 next = ccp->out.opt->next;
458 free(ccp->out.opt);
459 ccp->out.opt = next;
460 }
461 ccp_Setup(ccp);
462}
463
464static void
465CcpLayerFinish(struct fsm *fp)
466{
467 /* We're now down */
468 struct ccp *ccp = fsm2ccp(fp);
469 struct ccp_opt *next;
470
471 log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
472
473 /*
474 * Nuke options that may be left over from sending a REQ but never
475 * coming up.
476 */
477 while (ccp->out.opt) {
478 next = ccp->out.opt->next;
479 free(ccp->out.opt);
480 ccp->out.opt = next;
481 }
482
483 if (ccp_Required(ccp)) {
484 if (fp->link->lcp.fsm.state == ST_OPENED)
485 log_Printf(LogLCP, "%s: Closing due to CCP completion\n", fp->link->name);
486 fsm_Close(&fp->link->lcp.fsm);
487 }
488}
489
490/* Called when CCP has reached the OPEN state */
491static int
492CcpLayerUp(struct fsm *fp)
493{
494 /* We're now up */
495 struct ccp *ccp = fsm2ccp(fp);
496 struct ccp_opt **o;
497 int f, fail;
498
499 for (f = fail = 0; f < NALGORITHMS; f++)
500 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
501 (*algorithm[f]->Required)(&ccp->fsm) &&
502 (ccp->in.algorithm != f || ccp->out.algorithm != f)) {
503 /* Blow it all away - we haven't negotiated a required algorithm */
504 log_Printf(LogWARN, "%s: Failed to negotiate (required) %s\n",
505 fp->link->name, protoname(algorithm[f]->id));
506 fail = 1;
507 }
508
509 if (fail) {
510 ccp->his_proto = ccp->my_proto = -1;
511 fsm_Close(fp);
512 fsm_Close(&fp->link->lcp.fsm);
513 return 0;
514 }
515
516 log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
517
518 if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
519 ccp->in.algorithm < NALGORITHMS) {
520 ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
521 (fp->bundle, &ccp->in.opt);
522 if (ccp->in.state == NULL) {
523 log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
524 fp->link->name, protoname(ccp->his_proto));
525 ccp->his_proto = ccp->my_proto = -1;
526 fsm_Close(fp);
527 return 0;
528 }
529 }
530
531 o = &ccp->out.opt;
532 for (f = 0; f < ccp->out.algorithm; f++)
533 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]))
534 o = &(*o)->next;
535
536 if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
537 ccp->out.algorithm < NALGORITHMS) {
538 ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
539 (fp->bundle, &(*o)->val);
540 if (ccp->out.state == NULL) {
541 log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
542 fp->link->name, protoname(ccp->my_proto));
543 ccp->his_proto = ccp->my_proto = -1;
544 fsm_Close(fp);
545 return 0;
546 }
547 }
548
549 fp->more.reqs = fp->more.naks = fp->more.rejs = ccp->cfg.fsm.maxreq * 3;
550
551 log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
552 fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
553 protoname(ccp->his_proto), ccp->his_proto);
554
555 return 1;
556}
557
558static void
559CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
560 struct fsm_decode *dec)
561{
562 /* Deal with incoming data */
563 struct ccp *ccp = fsm2ccp(fp);
564 int f;
565 const char *disp;
566 struct fsm_opt *opt;
567
568 if (mode_type == MODE_REQ)
569 ccp->in.algorithm = -1; /* In case we've received two REQs in a row */
570
571 while (end - cp >= sizeof(opt->hdr)) {
572 if ((opt = fsm_readopt(&cp)) == NULL)
573 break;
574
575 for (f = NALGORITHMS-1; f > -1; f--)
576 if (algorithm[f]->id == opt->hdr.id)
577 break;
578
579 disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
580 if (disp == NULL)
581 disp = "";
582
583 log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
584 opt->hdr.len, disp);
585
586 if (f == -1) {
587 /* Don't understand that :-( */
588 if (mode_type == MODE_REQ) {
589 ccp->my_reject |= (1 << opt->hdr.id);
590 fsm_rej(dec, opt);
591 }
592 } else {
593 struct ccp_opt *o;
594
595 switch (mode_type) {
596 case MODE_REQ:
597 if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
598 (*algorithm[f]->Usable)(fp) &&
599 ccp->in.algorithm == -1) {
600 memcpy(&ccp->in.opt, opt, opt->hdr.len);
601 switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
602 case MODE_REJ:
603 fsm_rej(dec, &ccp->in.opt);
604 break;
605 case MODE_NAK:
606 fsm_nak(dec, &ccp->in.opt);
607 break;
608 case MODE_ACK:
609 fsm_ack(dec, &ccp->in.opt);
610 ccp->his_proto = opt->hdr.id;
611 ccp->in.algorithm = f; /* This one'll do :-) */
612 break;
613 }
614 } else {
615 fsm_rej(dec, opt);
616 }
617 break;
618 case MODE_NAK:
619 for (o = ccp->out.opt; o != NULL; o = o->next)
620 if (o->val.hdr.id == opt->hdr.id)
621 break;
622 if (o == NULL)
623 log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
624 " option\n", fp->link->name);
625 else {
626 memcpy(&o->val, opt, opt->hdr.len);
627 if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
628 MODE_ACK)
629 ccp->my_proto = algorithm[f]->id;
630 else {
631 ccp->his_reject |= (1 << opt->hdr.id);
632 ccp->my_proto = -1;
633 if (algorithm[f]->Required(fp)) {
634 log_Printf(LogWARN, "%s: Cannot understand peers (required)"
635 " %s negotiation\n", fp->link->name,
636 protoname(algorithm[f]->id));
637 fsm_Close(&fp->link->lcp.fsm);
638 }
639 }
640 }
641 break;
642 case MODE_REJ:
643 ccp->his_reject |= (1 << opt->hdr.id);
644 ccp->my_proto = -1;
645 if (algorithm[f]->Required(fp)) {
646 log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
647 fp->link->name, protoname(algorithm[f]->id));
648 fsm_Close(&fp->link->lcp.fsm);
649 }
650 break;
651 }
652 }
653 }
654
655 if (mode_type != MODE_NOP) {
656 fsm_opt_normalise(dec);
657 if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
658 if (ccp->in.state == NULL) {
659 ccp->his_proto = -1;
660 ccp->in.algorithm = -1;
661 }
662 }
663 }
664}
665
666extern struct mbuf *
667ccp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
668{
669 /* Got PROTO_CCP from link */
670 m_settype(bp, MB_CCPIN);
671 if (bundle_Phase(bundle) == PHASE_NETWORK)
672 fsm_Input(&l->ccp.fsm, bp);
673 else {
674 if (bundle_Phase(bundle) < PHASE_NETWORK)
675 log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
676 l->ccp.fsm.link->name, bundle_PhaseName(bundle));
677 m_freem(bp);
678 }
679 return NULL;
680}
681
682static void
683CcpRecvResetAck(struct fsm *fp, u_char id)
684{
685 /* Got a reset ACK, reset incoming dictionary */
686 struct ccp *ccp = fsm2ccp(fp);
687
688 if (ccp->reset_sent != -1) {
689 if (id != ccp->reset_sent) {
690 log_Printf(LogCCP, "%s: Incorrect ResetAck (id %d, not %d)"
691 " ignored\n", fp->link->name, id, ccp->reset_sent);
692 return;
693 }
694 /* Whaddaya know - a correct reset ack */
695 } else if (id == ccp->last_reset)
696 log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
697 fp->link->name);
698 else {
699 log_Printf(LogCCP, "%s: Unexpected ResetAck (id %d) ignored\n",
700 fp->link->name, id);
701 return;
702 }
703
704 ccp->last_reset = ccp->reset_sent;
705 ccp->reset_sent = -1;
706 if (ccp->in.state != NULL)
707 (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
708}
709
710static struct mbuf *
711ccp_LayerPush(struct bundle *b, struct link *l, struct mbuf *bp,
712 int pri, u_short *proto)
713{
714 if (PROTO_COMPRESSIBLE(*proto)) {
715 if (l->ccp.fsm.state != ST_OPENED) {
716 if (ccp_Required(&l->ccp)) {
717 /* The NCP layer shouldn't have let this happen ! */
718 log_Printf(LogERROR, "%s: Unexpected attempt to use an unopened and"
719 " required CCP layer\n", l->name);
720 m_freem(bp);
721 bp = NULL;
722 }
723 } else if (l->ccp.out.state != NULL) {
724 bp = (*algorithm[l->ccp.out.algorithm]->o.Write)
725 (l->ccp.out.state, &l->ccp, l, pri, proto, bp);
726 switch (*proto) {
727 case PROTO_ICOMPD:
728 m_settype(bp, MB_ICOMPDOUT);
729 break;
730 case PROTO_COMPD:
731 m_settype(bp, MB_COMPDOUT);
732 break;
733 }
734 }
735 }
736
737 return bp;
738}
739
740static struct mbuf *
741ccp_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto)
742{
743 /*
744 * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
745 * decompression routines so that the dictionary's updated
746 */
747 if (l->ccp.fsm.state == ST_OPENED) {
748 if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
749 log_Printf(LogDEBUG, "ccp_LayerPull: PROTO_%sCOMPDP -> PROTO_IP\n",
750 *proto == PROTO_ICOMPD ? "I" : "");
751 /* Decompress incoming data */
752 if (l->ccp.reset_sent != -1)
753 /* Send another REQ and put the packet in the bit bucket */
754 fsm_Output(&l->ccp.fsm, CODE_RESETREQ, l->ccp.reset_sent, NULL, 0,
755 MB_CCPOUT);
756 else if (l->ccp.in.state != NULL) {
757 bp = (*algorithm[l->ccp.in.algorithm]->i.Read)
758 (l->ccp.in.state, &l->ccp, proto, bp);
759 switch (*proto) {
760 case PROTO_ICOMPD:
761 m_settype(bp, MB_ICOMPDIN);
762 break;
763 case PROTO_COMPD:
764 m_settype(bp, MB_COMPDIN);
765 break;
766 }
767 return bp;
768 }
769 m_freem(bp);
770 bp = NULL;
771 } else if (PROTO_COMPRESSIBLE(*proto) && l->ccp.in.state != NULL) {
772 log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet (dict only)\n");
773 /* Add incoming Network Layer traffic to our dictionary */
774 (*algorithm[l->ccp.in.algorithm]->i.DictSetup)
775 (l->ccp.in.state, &l->ccp, *proto, bp);
776 } else
777 log_Printf(LogDEBUG, "ccp_LayerPull: Ignore packet\n");
778 }
779
780 return bp;
781}
782
783u_short
784ccp_Proto(struct ccp *ccp)
785{
786 return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
787 PROTO_COMPD : PROTO_ICOMPD;
788}
789
790int
791ccp_SetOpenMode(struct ccp *ccp)
792{
793 int f;
794
795 for (f = 0; f < CCP_NEG_TOTAL; f++)
796 if (IsEnabled(ccp->cfg.neg[f])) {
797 ccp->fsm.open_mode = 0;
798 return 1;
799 }
800
801 ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */
802
803 for (f = 0; f < CCP_NEG_TOTAL; f++)
804 if (IsAccepted(ccp->cfg.neg[f]))
805 return 1;
806
807 return 0; /* No CCP at all */
808}
809
810int
811ccp_DefaultUsable(struct fsm *fp)
812{
813 return 1;
814}
815
816int
817ccp_DefaultRequired(struct fsm *fp)
818{
819 return 0;
820}
821
822struct layer ccplayer = { LAYER_CCP, "ccp", ccp_LayerPush, ccp_LayerPull };