xref: /freebsd/usr.sbin/ppp/ccp.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
1 /*
2  *	   PPP Compression Control Protocol (CCP) Module
3  *
4  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5  *
6  *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the Internet Initiative Japan, Inc.  The name of the
14  * IIJ may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * $Id: ccp.c,v 1.39 1998/08/26 17:39:36 brian Exp $
21  *
22  *	TODO:
23  *		o Support other compression protocols
24  */
25 #include <sys/types.h>
26 #include <netinet/in.h>
27 #include <netinet/in_systm.h>
28 #include <netinet/ip.h>
29 #include <sys/un.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <termios.h>
35 
36 #include "defs.h"
37 #include "command.h"
38 #include "mbuf.h"
39 #include "log.h"
40 #include "timer.h"
41 #include "fsm.h"
42 #include "lcpproto.h"
43 #include "lcp.h"
44 #include "ccp.h"
45 #include "pred.h"
46 #include "deflate.h"
47 #include "throughput.h"
48 #include "iplist.h"
49 #include "slcompress.h"
50 #include "lqr.h"
51 #include "hdlc.h"
52 #include "ipcp.h"
53 #include "filter.h"
54 #include "descriptor.h"
55 #include "prompt.h"
56 #include "link.h"
57 #include "mp.h"
58 #include "async.h"
59 #include "physical.h"
60 #include "bundle.h"
61 
62 static void CcpSendConfigReq(struct fsm *);
63 static void CcpSentTerminateReq(struct fsm *);
64 static void CcpSendTerminateAck(struct fsm *, u_char);
65 static void CcpDecodeConfig(struct fsm *, u_char *, int, int,
66                             struct fsm_decode *);
67 static void CcpLayerStart(struct fsm *);
68 static void CcpLayerFinish(struct fsm *);
69 static int CcpLayerUp(struct fsm *);
70 static void CcpLayerDown(struct fsm *);
71 static void CcpInitRestartCounter(struct fsm *);
72 static void CcpRecvResetReq(struct fsm *);
73 static void CcpRecvResetAck(struct fsm *, u_char);
74 
75 static struct fsm_callbacks ccp_Callbacks = {
76   CcpLayerUp,
77   CcpLayerDown,
78   CcpLayerStart,
79   CcpLayerFinish,
80   CcpInitRestartCounter,
81   CcpSendConfigReq,
82   CcpSentTerminateReq,
83   CcpSendTerminateAck,
84   CcpDecodeConfig,
85   CcpRecvResetReq,
86   CcpRecvResetAck
87 };
88 
89 static const char *ccp_TimerNames[] =
90   {"CCP restart", "CCP openmode", "CCP stopped"};
91 
92 static char const *cftypes[] = {
93   /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */
94   "OUI",		/* 0: OUI */
95   "PRED1",		/* 1: Predictor type 1 */
96   "PRED2",		/* 2: Predictor type 2 */
97   "PUDDLE",		/* 3: Puddle Jumber */
98   "???", "???", "???", "???", "???", "???",
99   "???", "???", "???", "???", "???", "???",
100   "HWPPC",		/* 16: Hewlett-Packard PPC */
101   "STAC",		/* 17: Stac Electronics LZS (rfc1974) */
102   "MPPC",		/* 18: Microsoft PPC (rfc2118) */
103   "GAND",		/* 19: Gandalf FZA (rfc1993) */
104   "V42BIS",		/* 20: ARG->DATA.42bis compression */
105   "BSD",		/* 21: BSD LZW Compress */
106   "???",
107   "LZS-DCP",		/* 23: LZS-DCP Compression Protocol (rfc1967) */
108   "MAGNALINK/DEFLATE",	/* 24: Magnalink Variable Resource (rfc1975) */
109 			/* 24: Deflate (according to pppd-2.3.*) */
110   "DCE",		/* 25: Data Circuit-Terminating Equip (rfc1976) */
111   "DEFLATE",		/* 26: Deflate (rfc1979) */
112 };
113 
114 #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
115 
116 static const char *
117 protoname(int proto)
118 {
119   if (proto < 0 || proto > NCFTYPES)
120     return "none";
121   return cftypes[proto];
122 }
123 
124 /* We support these algorithms, and Req them in the given order */
125 static const struct ccp_algorithm *algorithm[] = {
126   &DeflateAlgorithm,
127   &Pred1Algorithm,
128   &PppdDeflateAlgorithm
129 };
130 
131 #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0])
132 
133 int
134 ccp_ReportStatus(struct cmdargs const *arg)
135 {
136   struct link *l;
137   struct ccp *ccp;
138 
139   l = command_ChooseLink(arg);
140   ccp = &l->ccp;
141 
142   prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name,
143                 State2Nam(ccp->fsm.state));
144   prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n",
145                 protoname(ccp->my_proto), protoname(ccp->his_proto));
146   prompt_Printf(arg->prompt, " Output: %ld --> %ld,  Input: %ld --> %ld\n",
147                 ccp->uncompout, ccp->compout,
148                 ccp->compin, ccp->uncompin);
149 
150   prompt_Printf(arg->prompt, "\n Defaults: ");
151   prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry);
152   prompt_Printf(arg->prompt, "           deflate windows: ");
153   prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize);
154   prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize);
155   prompt_Printf(arg->prompt, "           DEFLATE:    %s\n",
156                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE]));
157   prompt_Printf(arg->prompt, "           PREDICTOR1: %s\n",
158                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1]));
159   prompt_Printf(arg->prompt, "           DEFLATE24:  %s\n",
160                 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24]));
161   return 0;
162 }
163 
164 void
165 ccp_SetupCallbacks(struct ccp *ccp)
166 {
167   ccp->fsm.fn = &ccp_Callbacks;
168   ccp->fsm.FsmTimer.name = ccp_TimerNames[0];
169   ccp->fsm.OpenTimer.name = ccp_TimerNames[1];
170   ccp->fsm.StoppedTimer.name = ccp_TimerNames[2];
171 }
172 
173 void
174 ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l,
175          const struct fsm_parent *parent)
176 {
177   /* Initialise ourselves */
178 
179   fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP,
180            bundle, l, parent, &ccp_Callbacks, ccp_TimerNames);
181 
182   ccp->cfg.deflate.in.winsize = 0;
183   ccp->cfg.deflate.out.winsize = 15;
184   ccp->cfg.fsmretry = DEF_FSMRETRY;
185   ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED;
186   ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED;
187   ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0;
188 
189   ccp_Setup(ccp);
190 }
191 
192 void
193 ccp_Setup(struct ccp *ccp)
194 {
195   /* Set ourselves up for a startup */
196   ccp->fsm.open_mode = 0;
197   ccp->fsm.maxconfig = 10;
198   ccp->his_proto = ccp->my_proto = -1;
199   ccp->reset_sent = ccp->last_reset = -1;
200   ccp->in.algorithm = ccp->out.algorithm = -1;
201   ccp->in.state = ccp->out.state = NULL;
202   ccp->in.opt.id = -1;
203   ccp->out.opt = NULL;
204   ccp->his_reject = ccp->my_reject = 0;
205   ccp->uncompout = ccp->compout = 0;
206   ccp->uncompin = ccp->compin = 0;
207 }
208 
209 static void
210 CcpInitRestartCounter(struct fsm *fp)
211 {
212   /* Set fsm timer load */
213   struct ccp *ccp = fsm2ccp(fp);
214 
215   fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS;
216   fp->restart = DEF_REQs;
217 }
218 
219 static void
220 CcpSendConfigReq(struct fsm *fp)
221 {
222   /* Send config REQ please */
223   struct ccp *ccp = fsm2ccp(fp);
224   struct ccp_opt **o;
225   u_char *cp, buff[100];
226   int f, alloc;
227 
228   cp = buff;
229   o = &ccp->out.opt;
230   alloc = ccp->his_reject == 0 && ccp->out.opt == NULL;
231   ccp->my_proto = -1;
232   ccp->out.algorithm = -1;
233   for (f = 0; f < NALGORITHMS; f++)
234     if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) &&
235         !REJECTED(ccp, algorithm[f]->id)) {
236 
237       if (!alloc)
238         for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next)
239           if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f)
240             break;
241 
242       if (alloc || *o == NULL) {
243         *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt));
244         (*o)->val.id = algorithm[f]->id;
245         (*o)->val.len = 2;
246         (*o)->next = NULL;
247         (*o)->algorithm = f;
248         (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
249       }
250 
251       if (cp + (*o)->val.len > buff + sizeof buff) {
252         log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name);
253         break;
254       }
255       memcpy(cp, &(*o)->val, (*o)->val.len);
256       cp += (*o)->val.len;
257 
258       ccp->my_proto = (*o)->val.id;
259       ccp->out.algorithm = f;
260 
261       if (alloc)
262         o = &(*o)->next;
263     }
264 
265   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff);
266 }
267 
268 void
269 ccp_SendResetReq(struct fsm *fp)
270 {
271   /* We can't read our input - ask peer to reset */
272   struct ccp *ccp = fsm2ccp(fp);
273 
274   ccp->reset_sent = fp->reqid;
275   ccp->last_reset = -1;
276   fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0);
277 }
278 
279 static void
280 CcpSentTerminateReq(struct fsm *fp)
281 {
282   /* Term REQ just sent by FSM */
283 }
284 
285 static void
286 CcpSendTerminateAck(struct fsm *fp, u_char id)
287 {
288   /* Send Term ACK please */
289   fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
290 }
291 
292 static void
293 CcpRecvResetReq(struct fsm *fp)
294 {
295   /* Got a reset REQ, reset outgoing dictionary */
296   struct ccp *ccp = fsm2ccp(fp);
297   if (ccp->out.state != NULL)
298     (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state);
299 }
300 
301 static void
302 CcpLayerStart(struct fsm *fp)
303 {
304   /* We're about to start up ! */
305   log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name);
306 }
307 
308 static void
309 CcpLayerDown(struct fsm *fp)
310 {
311   /* About to come down */
312   struct ccp *ccp = fsm2ccp(fp);
313   struct ccp_opt *next;
314 
315   log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name);
316   if (ccp->in.state != NULL) {
317     (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state);
318     ccp->in.state = NULL;
319     ccp->in.algorithm = -1;
320   }
321   if (ccp->out.state != NULL) {
322     (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state);
323     ccp->out.state = NULL;
324     ccp->out.algorithm = -1;
325   }
326   ccp->his_reject = ccp->my_reject = 0;
327 
328   while (ccp->out.opt) {
329     next = ccp->out.opt->next;
330     free(ccp->out.opt);
331     ccp->out.opt = next;
332   }
333   ccp_Setup(ccp);
334 }
335 
336 static void
337 CcpLayerFinish(struct fsm *fp)
338 {
339   /* We're now down */
340   log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name);
341 }
342 
343 /*
344  *  Called when CCP has reached the OPEN state
345  */
346 static int
347 CcpLayerUp(struct fsm *fp)
348 {
349   /* We're now up */
350   struct ccp *ccp = fsm2ccp(fp);
351   log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name);
352   if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
353       ccp->in.algorithm < NALGORITHMS) {
354     ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
355     if (ccp->in.state == NULL) {
356       log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
357                 fp->link->name, protoname(ccp->his_proto));
358       ccp->his_proto = ccp->my_proto = -1;
359       fsm_Close(fp);
360     }
361   }
362 
363   if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
364       ccp->out.algorithm < NALGORITHMS) {
365     ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
366                        (&ccp->out.opt->val);
367     if (ccp->out.state == NULL) {
368       log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
369                 fp->link->name, protoname(ccp->my_proto));
370       ccp->his_proto = ccp->my_proto = -1;
371       fsm_Close(fp);
372     }
373   }
374 
375   log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n",
376             fp->link->name, protoname(ccp->my_proto), ccp->my_proto,
377             protoname(ccp->his_proto), ccp->his_proto);
378   return 1;
379 }
380 
381 static void
382 CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
383                 struct fsm_decode *dec)
384 {
385   /* Deal with incoming data */
386   struct ccp *ccp = fsm2ccp(fp);
387   int type, length;
388   int f;
389   const char *end;
390 
391   while (plen >= sizeof(struct fsmconfig)) {
392     type = *cp;
393     length = cp[1];
394 
395     if (length == 0) {
396       log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name);
397       break;
398     }
399 
400     if (length > sizeof(struct lcp_opt)) {
401       length = sizeof(struct lcp_opt);
402       log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n",
403                 fp->link->name, length);
404     }
405 
406     for (f = NALGORITHMS-1; f > -1; f--)
407       if (algorithm[f]->id == type)
408         break;
409 
410     end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp);
411     if (end == NULL)
412       end = "";
413 
414     if (type < NCFTYPES)
415       log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end);
416     else
417       log_Printf(LogCCP, " ???[%d] %s\n", length, end);
418 
419     if (f == -1) {
420       /* Don't understand that :-( */
421       if (mode_type == MODE_REQ) {
422         ccp->my_reject |= (1 << type);
423         memcpy(dec->rejend, cp, length);
424         dec->rejend += length;
425       }
426     } else {
427       struct ccp_opt *o;
428 
429       switch (mode_type) {
430       case MODE_REQ:
431 	if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
432             ccp->in.algorithm == -1) {
433 	  memcpy(&ccp->in.opt, cp, length);
434           switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
435           case MODE_REJ:
436 	    memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len);
437 	    dec->rejend += ccp->in.opt.len;
438             break;
439           case MODE_NAK:
440 	    memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len);
441 	    dec->nakend += ccp->in.opt.len;
442             break;
443           case MODE_ACK:
444 	    memcpy(dec->ackend, cp, length);
445 	    dec->ackend += length;
446 	    ccp->his_proto = type;
447             ccp->in.algorithm = f;		/* This one'll do :-) */
448             break;
449           }
450 	} else {
451 	  memcpy(dec->rejend, cp, length);
452 	  dec->rejend += length;
453 	}
454 	break;
455       case MODE_NAK:
456         for (o = ccp->out.opt; o != NULL; o = o->next)
457           if (o->val.id == cp[0])
458             break;
459         if (o == NULL)
460           log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n",
461                     fp->link->name);
462         else {
463 	  memcpy(&o->val, cp, length);
464           if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK)
465             ccp->my_proto = algorithm[f]->id;
466           else {
467 	    ccp->his_reject |= (1 << type);
468 	    ccp->my_proto = -1;
469           }
470         }
471         break;
472       case MODE_REJ:
473 	ccp->his_reject |= (1 << type);
474 	ccp->my_proto = -1;
475 	break;
476       }
477     }
478 
479     plen -= cp[1];
480     cp += cp[1];
481   }
482 
483   if (mode_type != MODE_NOP) {
484     if (dec->rejend != dec->rej) {
485       /* rejects are preferred */
486       dec->ackend = dec->ack;
487       dec->nakend = dec->nak;
488       if (ccp->in.state == NULL) {
489         ccp->his_proto = -1;
490         ccp->in.algorithm = -1;
491       }
492     } else if (dec->nakend != dec->nak) {
493       /* then NAKs */
494       dec->ackend = dec->ack;
495       if (ccp->in.state == NULL) {
496         ccp->his_proto = -1;
497         ccp->in.algorithm = -1;
498       }
499     }
500   }
501 }
502 
503 void
504 ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp)
505 {
506   /* Got PROTO_CCP from link */
507   if (bundle_Phase(bundle) == PHASE_NETWORK)
508     fsm_Input(&ccp->fsm, bp);
509   else {
510     if (bundle_Phase(bundle) < PHASE_NETWORK)
511       log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n",
512                  ccp->fsm.link->name, bundle_PhaseName(bundle));
513     mbuf_Free(bp);
514   }
515 }
516 
517 static void
518 CcpRecvResetAck(struct fsm *fp, u_char id)
519 {
520   /* Got a reset ACK, reset incoming dictionary */
521   struct ccp *ccp = fsm2ccp(fp);
522 
523   if (ccp->reset_sent != -1) {
524     if (id != ccp->reset_sent) {
525       log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)"
526                 " ignored\n", fp->link->name, id, ccp->reset_sent);
527       return;
528     }
529     /* Whaddaya know - a correct reset ack */
530   } else if (id == ccp->last_reset)
531     log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n",
532               fp->link->name);
533   else {
534     log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n",
535               fp->link->name, id);
536     return;
537   }
538 
539   ccp->last_reset = ccp->reset_sent;
540   ccp->reset_sent = -1;
541   if (ccp->in.state != NULL)
542     (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state);
543 }
544 
545 int
546 ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto,
547              struct mbuf *m)
548 {
549   /*
550    * Compress outgoing data.  It's already deemed to be suitable Network
551    * Layer data.
552    */
553   if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL)
554     return (*algorithm[ccp->out.algorithm]->o.Write)
555              (ccp->out.state, ccp, l, pri, proto, m);
556   return 0;
557 }
558 
559 struct mbuf *
560 ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp)
561 {
562   /*
563    * If proto isn't PROTO_[I]COMPD, we still want to pass it to the
564    * decompression routines so that the dictionary's updated
565    */
566   if (ccp->fsm.state == ST_OPENED) {
567     if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) {
568       /* Decompress incoming data */
569       if (ccp->reset_sent != -1)
570         /* Send another REQ and put the packet in the bit bucket */
571         fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0);
572       else if (ccp->in.state != NULL)
573         return (*algorithm[ccp->in.algorithm]->i.Read)
574                  (ccp->in.state, ccp, proto, bp);
575       mbuf_Free(bp);
576       bp = NULL;
577     } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL)
578       /* Add incoming Network Layer traffic to our dictionary */
579       (*algorithm[ccp->in.algorithm]->i.DictSetup)
580         (ccp->in.state, ccp, *proto, bp);
581   }
582 
583   return bp;
584 }
585 
586 u_short
587 ccp_Proto(struct ccp *ccp)
588 {
589   return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ?
590          PROTO_COMPD : PROTO_ICOMPD;
591 }
592 
593 int
594 ccp_SetOpenMode(struct ccp *ccp)
595 {
596   int f;
597 
598   for (f = 0; f < CCP_NEG_TOTAL; f++)
599     if (IsEnabled(ccp->cfg.neg[f])) {
600       ccp->fsm.open_mode = 0;
601       return 1;
602     }
603 
604   ccp->fsm.open_mode = OPEN_PASSIVE;	/* Go straight to ST_STOPPED ? */
605 
606   for (f = 0; f < CCP_NEG_TOTAL; f++)
607     if (IsAccepted(ccp->cfg.neg[f]))
608       return 1;
609 
610   return 0;				/* No CCP at all */
611 }
612