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