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